From 007d7b6e1e6bf450f542e5f9f98e3441fae839f4 Mon Sep 17 00:00:00 2001 From: "mjw@wray-m-3.hpl.hp.com" Date: Fri, 13 May 2005 15:08:29 +0000 Subject: [PATCH] bitkeeper revision 1.1403 (4284c2edzLTGTr4gHmGzYsZMuetTRQ) Switch to using unix-domain interface on xend instead of http via libcurl. Sundry other merges and fixes. Signed-off-by: Mike Wray --- .rootkeys | 2 + tools/libxutil/fd_stream.c | 184 ++++ tools/libxutil/fd_stream.h | 36 + tools/libxutil/lexis.h | 2 +- tools/libxutil/sxpr.c | 484 ++++++--- tools/libxutil/sxpr.h | 252 ++--- tools/libxutil/sxpr_parser.c | 1107 +++++++++++---------- tools/libxutil/sxpr_parser.h | 70 +- tools/libxutil/sys_string.c | 55 + tools/libxutil/sys_string.h | 1 + tools/python/xen/xend/server/SrvDaemon.py | 6 +- tools/python/xen/xend/server/event.py | 46 +- tools/xfrd/Make.xfrd | 3 +- tools/xfrd/Makefile | 15 +- tools/xfrd/connection.c | 2 +- tools/xfrd/lzi_stream.c | 5 +- tools/xfrd/xen_domain.c | 391 +++----- tools/xfrd/xfrd.c | 8 +- 18 files changed, 1607 insertions(+), 1062 deletions(-) create mode 100644 tools/libxutil/fd_stream.c create mode 100644 tools/libxutil/fd_stream.h diff --git a/.rootkeys b/.rootkeys index df709f294d..b70a81dd50 100644 --- a/.rootkeys +++ b/.rootkeys @@ -754,6 +754,8 @@ 41a216cav5JJbtDQnusfuMa_1x_Xpw tools/libxutil/debug.h 40e9808eyjiahG5uF6AMelNVujBzCg tools/libxutil/enum.c 40e9808eZpbdn9q2KSSMGCNvY_ZgpQ tools/libxutil/enum.h +4284c2ecWyadIhHF1u_QSgWqIXkaLA tools/libxutil/fd_stream.c +4284c2ecEOOcF6fZUf_NsZzYAoNo-w tools/libxutil/fd_stream.h 40e03332p5Dc_owJQRuN72ymJZddFQ tools/libxutil/file_stream.c 40e03332jWfB2viAhLSkq1WK0r_iDQ tools/libxutil/file_stream.h 40e03332rUjNMGg11n2rN6V4DCrvOg tools/libxutil/gzip_stream.c diff --git a/tools/libxutil/fd_stream.c b/tools/libxutil/fd_stream.c new file mode 100644 index 0000000000..428f0a5ff0 --- /dev/null +++ b/tools/libxutil/fd_stream.c @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2004 Mike Wray + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/** @file + * An IOStream implementation using fds. + */ +#ifndef __KERNEL__ + +#include +#include +#include +#include +#include +#include "allocate.h" +#include "fd_stream.h" + +#define MODULE_NAME "fd_stream" +#define DEBUG 1 +//#undef DEBUG +#include "debug.h" + +static int fd_read(IOStream *s, void *buf, size_t n); +static int fd_write(IOStream *s, const void *buf, size_t n); +static int fd_error(IOStream *s); +static int fd_close(IOStream *s); +static void fd_free(IOStream *s); +static int fd_flush(IOStream *s); + +/** Methods used by a fd IOStream. */ +static const IOMethods fd_methods = { + read: fd_read, + write: fd_write, + error: fd_error, + close: fd_close, + free: fd_free, + flush: fd_flush, +}; + +/** Get the fd data. + * + * @param io fd stream + * @return data + */ +static inline FDData * fd_data(IOStream *io){ + return (FDData *)io->data; +} + +/** Test if a stream is a fd stream. + * + * @param io stream + * @return 0 if a fd stream, -EINVAL if not + */ +int fd_stream_check(IOStream *io){ + return (io && io->methods == &fd_methods ? 0 : -EINVAL); +} + +/** Get the data for a fd stream. + * + * @param io stream + * @param data return value for the data + * @return 0 if a fd stream, -EINVAL if not + */ +int fd_stream_data(IOStream *io, FDData **data){ + int err = fd_stream_check(io); + if(err){ + *data = NULL; + } else { + *data = fd_data(io); + } + return err; +} + + +/** Write to the underlying fd. + * + * @param stream input + * @param buf where to put input + * @param n number of bytes to write + * @return number of bytes written + */ +static int fd_write(IOStream *s, const void *buf, size_t n){ + FDData *data = fd_data(s); + int k; + k = write(data->fd, buf, n); + return k; +} + +/** Read from the underlying stream; + * + * @param stream input + * @param buf where to put input + * @param n number of bytes to read + * @return number of bytes read + */ +static int fd_read(IOStream *s, void *buf, size_t n){ + FDData *data = fd_data(s); + int k; + k = read(data->fd, buf, n); + //printf("> fd_read> buf=%p n=%d --> k=%d\n", buf, n, k); + return k; +} + +/** Flush the fd (no-op). + * + * @param s fd stream + * @return 0 on success, error code otherwise + */ +static int fd_flush(IOStream *s){ + return 0; +} + +/** Check if a fd stream has an error (no-op). + * + * @param s fd stream + * @return 1 if has an error, 0 otherwise + */ +static int fd_error(IOStream *s){ + return 0; +} + +/** Close a fd stream. + * + * @param s fd stream to close + * @return result of the close + */ +static int fd_close(IOStream *s){ + FDData *data = fd_data(s); + return close(data->fd); +} + +/** Free a fd stream. + * + * @param s fd stream + */ +static void fd_free(IOStream *s){ + FDData *data = fd_data(s); + deallocate(data); +} + +/** Create an IOStream for a fd. + * + * @param fd fd to wtap + * @return new IOStream using fd for i/o + */ +IOStream *fd_stream_new(int fd){ + int err = -ENOMEM; + IOStream *io = NULL; + FDData *data = NULL; + + io = ALLOCATE(IOStream); + if(!io) goto exit; + io->methods = &fd_methods; + data = ALLOCATE(FDData); + if(!data) goto exit; + io->data = data; + data->fd = fd; + err = 0; + exit: + if(err){ + if(io){ + if(data) deallocate(data); + deallocate(io); + io = NULL; + } + } + return io; +} + +#endif diff --git a/tools/libxutil/fd_stream.h b/tools/libxutil/fd_stream.h new file mode 100644 index 0000000000..b37a6863e2 --- /dev/null +++ b/tools/libxutil/fd_stream.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2004 Mike Wray + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _XMC_FD_STREAM_H_ +#define _XMC_FD_STREAM_H_ + +#ifndef __KERNEL__ +#include "iostream.h" + +/** Data associated with a fd stream. */ +typedef struct FDData { + /** The socket file descriptor. */ + int fd; +} FDData; + +extern IOStream *fd_stream_new(int fd); +extern int fd_stream_data(IOStream *io, FDData **data); +extern int fd_stream_check(IOStream *io); + +#endif +#endif /* !_XMC_FD_STREAM_H_ */ diff --git a/tools/libxutil/lexis.h b/tools/libxutil/lexis.h index be8fb653d3..d49a3547d6 100644 --- a/tools/libxutil/lexis.h +++ b/tools/libxutil/lexis.h @@ -34,7 +34,7 @@ #define space_class ((char []){ '\n', '\r', '\t', ' ', '\f' , 0 }) /** Class of separator characters. */ -#define sep_class "{}()<>[]@!;" +#define sep_class "{}()<>[]!;\"'" #define comment_class "#" diff --git a/tools/libxutil/sxpr.c b/tools/libxutil/sxpr.c index 02a5040b52..d264527f25 100644 --- a/tools/libxutil/sxpr.c +++ b/tools/libxutil/sxpr.c @@ -28,6 +28,19 @@ #include #endif +#ifdef __KERNEL__ +#include + +int rand(void){ + int v; + get_random_bytes(&v, sizeof(v)); + return v; +} + +#else +#include +#endif + #undef free /** @file @@ -42,41 +55,51 @@ static int atom_print(IOStream *io, Sxpr obj, unsigned flags); static int atom_equal(Sxpr x, Sxpr y); static void atom_free(Sxpr obj); +static Sxpr atom_copy(Sxpr obj); static int string_print(IOStream *io, Sxpr obj, unsigned flags); static int string_equal(Sxpr x, Sxpr y); static void string_free(Sxpr obj); +static Sxpr string_copy(Sxpr obj); static int cons_print(IOStream *io, Sxpr obj, unsigned flags); static int cons_equal(Sxpr x, Sxpr y); static void cons_free(Sxpr obj); +static Sxpr cons_copy(Sxpr obj); static int null_print(IOStream *io, Sxpr obj, unsigned flags); static int none_print(IOStream *io, Sxpr obj, unsigned flags); static int int_print(IOStream *io, Sxpr obj, unsigned flags); static int bool_print(IOStream *io, Sxpr obj, unsigned flags); +static int err_print(IOStream *io, Sxpr obj, unsigned flags); +static int nomem_print(IOStream *io, Sxpr obj, unsigned flags); /** Type definitions. */ static SxprType types[1024] = { - [T_NONE] { type: T_NONE, name: "none", print: none_print }, - [T_NULL] { type: T_NULL, name: "null", print: null_print }, - [T_UINT] { type: T_UINT, name: "int", print: int_print, }, - [T_BOOL] { type: T_BOOL, name: "bool", print: bool_print, }, - [T_ATOM] { type: T_ATOM, name: "atom", print: atom_print, - pointer: TRUE, - free: atom_free, - equal: atom_equal, - }, - [T_STRING] { type: T_STRING, name: "string", print: string_print, - pointer: TRUE, - free: string_free, - equal: string_equal, - }, - [T_CONS] { type: T_CONS, name: "cons", print: cons_print, - pointer: TRUE, - free: cons_free, - equal: cons_equal, - }, + [T_NONE] { .type= T_NONE, .name= "none", .print= none_print }, + [T_NULL] { .type= T_NULL, .name= "null", .print= null_print }, + [T_UINT] { .type= T_UINT, .name= "int", .print= int_print, }, + [T_BOOL] { .type= T_BOOL, .name= "bool", .print= bool_print, }, + [T_ERR] { .type= T_ERR, .name= "err", .print= err_print, }, + [T_NOMEM] { .type= T_ERR, .name= "nomem", .print= nomem_print, }, + [T_ATOM] { .type= T_ATOM, .name= "atom", .print= atom_print, + .pointer= TRUE, + .free= atom_free, + .equal= atom_equal, + .copy= atom_copy, + }, + [T_STRING] { .type= T_STRING, .name= "string", .print= string_print, + .pointer= TRUE, + .free= string_free, + .equal= string_equal, + .copy= string_copy, + }, + [T_CONS] { .type= T_CONS, .name= "cons", .print= cons_print, + .pointer= TRUE, + .free= cons_free, + .equal= cons_equal, + .copy= cons_copy, + }, }; /** Number of entries in the types array. */ @@ -157,12 +180,29 @@ int objprint(IOStream *io, Sxpr x, unsigned flags){ int k = 0; if(!io) return k; if(flags & PRINT_TYPE){ - k += IOStream_print(io, "%s:", def->name); + k += IOStream_print(io, "%s:", def->name); + } + if(def->pointer && (flags & PRINT_ADDR)){ + k += IOStream_print(io, "<%p>", get_ptr(x)); } k += print_fn(io, x, flags); return k; } +Sxpr objcopy(Sxpr x){ + SxprType *def = get_sxpr_type(get_type(x)); + ObjCopyFn *copy_fn = (def ? def->copy : NULL); + Sxpr v; + if(copy_fn){ + v = copy_fn(x); + } else if(def->pointer){ + v = ONOMEM; + } else { + v = x; + } + return v; +} + /** General sxpr free function. * Frees an sxpr using the free function for its type. * Free functions must recursively free any subsxprs. @@ -176,11 +216,11 @@ void objfree(Sxpr x){ SxprType *def = get_sxpr_type(get_type(x)); if(def){ - if(def->free){ - def->free(x); - } else if (def->pointer){ - hfree(x); - } + if(def->free){ + def->free(x); + } else if (def->pointer){ + hfree(x); + } } } @@ -284,9 +324,9 @@ Sxpr cons_member_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v){ */ int cons_subset(Sxpr s, Sxpr t){ for( ; CONSP(t); t = CDR(t)){ - if(!CONSP(cons_member(s, CAR(t)))){ - return 0; - } + if(!CONSP(cons_member(s, CAR(t)))){ + return 0; + } } return 1; } @@ -365,18 +405,27 @@ Sxpr setf(Sxpr k, Sxpr v, Sxpr l){ #endif /* USE_GC */ /** Create a new atom with the given name. + * Makes an integer sxpr if the name can be parsed as an int. * * @param name the name * @return new atom */ Sxpr atom_new(char *name){ Sxpr n, obj = ONOMEM; + long v; - n = string_new(name); - if(NOMEMP(n)) goto exit; - obj = HALLOC(ObjAtom, T_ATOM); - if(NOMEMP(obj)) goto exit; - OBJ_ATOM(obj)->name = n; + if(convert_atol(name, &v) == 0){ + obj = OINT(v); + } else { + n = string_new(name); + if(NOMEMP(n)) goto exit; + obj = HALLOC(ObjAtom, T_ATOM); + if(NOMEMP(obj)){ + string_free(n); + goto exit; + } + OBJ_ATOM(obj)->name = n; + } exit: return obj; } @@ -392,6 +441,20 @@ void atom_free(Sxpr obj){ hfree(obj); } +/** Copy an atom. + * + * @param obj to copy + */ +Sxpr atom_copy(Sxpr obj){ + Sxpr v; + if(OBJ_ATOM(obj)->interned){ + v = obj; + } else { + v = atom_new(atom_name(obj)); + } + return v; +} + /** Print an atom. Prints the atom name. * * @param io stream to print to @@ -400,8 +463,7 @@ void atom_free(Sxpr obj){ * @return number of bytes printed */ int atom_print(IOStream *io, Sxpr obj, unsigned flags){ - //return string_print(io, OBJ_ATOM(obj)->name, (flags | PRINT_RAW)); - return string_print(io, OBJ_ATOM(obj)->name, flags); + return objprint(io, OBJ_ATOM(obj)->name, flags); } /** Atom equality. @@ -430,13 +492,17 @@ char * atom_name(Sxpr obj){ return string_string(OBJ_ATOM(obj)->name); } +int atom_length(Sxpr obj){ + return string_length(OBJ_ATOM(obj)->name); +} + /** Get the C string from a string sxpr. * * @param obj string sxpr * @return string */ char * string_string(Sxpr obj){ - return OBJ_STRING(obj); + return OBJ_STRING(obj)->data; } /** Get the length of a string. @@ -445,7 +511,7 @@ char * string_string(Sxpr obj){ * @return length */ int string_length(Sxpr obj){ - return strlen(OBJ_STRING(obj)); + return OBJ_STRING(obj)->len; } /** Create a new string. The input string is copied, @@ -456,12 +522,28 @@ int string_length(Sxpr obj){ */ Sxpr string_new(char *s){ int n = (s ? strlen(s) : 0); + return string_new_n(s, n); +} + +/** Create a new string. The input string is copied, + * and need not be null-terminated. + * + * @param s characters to put in the string (may be null) + * @param n string length + * @return new sxpr + */ +Sxpr string_new_n(char *s, int n){ Sxpr obj; - obj = halloc(n+1, T_STRING); + obj = halloc(sizeof(ObjString) + n + 1, T_STRING); if(!NOMEMP(obj)){ - char *str = OBJ_STRING(obj); - strncpy(str, s, n); - str[n] = '\0'; + char *str = OBJ_STRING(obj)->data; + OBJ_STRING(obj)->len = n; + if(s){ + memcpy(str, s, n); + str[n] = '\0'; + } else { + memset(str, 0, n + 1); + } } return obj; } @@ -474,70 +556,180 @@ void string_free(Sxpr obj){ hfree(obj); } +/** Copy a string. + * + * @param obj to copy + */ +Sxpr string_copy(Sxpr obj){ + return string_new_n(string_string(obj), string_length(obj)); +} + /** Determine if a string needs escapes when printed * using the given flags. * * @param str string to check + * @param n string length * @param flags print flags * @return 1 if needs escapes, 0 otherwise */ -int needs_escapes(char *str, unsigned flags){ +int needs_escapes(char *str, int n, unsigned flags){ char *c; + int i; int val = 0; if(str){ - for(c=str; *c; c++){ - if(in_alpha_class(*c)) continue; - if(in_decimal_digit_class(*c)) continue; - if(in_class(*c, "/._+:@~-")) continue; - val = 1; - break; - } - } - //printf("\n> val=%d str=|%s|\n", val, str); + for(i=0, c=str; i> 16) & 0xff; + if('a' <= c && c <= 'z') break; + } + return c; +} + +int string_contains(char *s, int s_n, char *k, int k_n){ + int i, n = s_n - k_n; + for(i=0; i < n; i++){ + if(!memcmp(s+i, k, k_n)) return 1; + } + return 0; +} + +int string_delim(char *s, int s_n, char *d, int d_n){ + int i; + if(d_n < 4) return -1; + memset(d, 0, d_n+1); + for(i=0; i<3; i++){ + d[i] = randchar(); + } + for( ; i < d_n; i++){ + if(!string_contains(s, s_n, d, i)){ + return i; + } + d[i] = randchar(); + } + return -1; +} + +/** Print the bytes in a string as-is. + * + * @param io stream + * @param str string + * @param n length + * @return bytes written or error code + */ +int _string_print_raw(IOStream *io, char *str, int n){ + int k = 0; + k = IOStream_write(io, str, n); + return k; +} + +/** Print a string in counted data format. + * + * @param io stream + * @param str string + * @param n length + * @return bytes written or error code + */ +int _string_print_counted(IOStream *io, char *str, int n){ + int k = 0; + k += IOStream_print(io, "%c%c%d%c", + c_data_open, c_data_count, n, c_data_count); + k += IOStream_write(io, str, n); + return k; +} + +/** Print a string in quoted data format. + * + * @param io stream + * @param str string + * @param n length + * @return bytes written or error code + */ +int _string_print_quoted(IOStream *io, char *str, int n){ + int k = 0; + char d[10]; + int d_n; + d_n = string_delim(str, n, d, sizeof(d) - 1); + k += IOStream_print(io, "%c%c%s%c", + c_data_open, c_data_quote, d, c_data_quote); + k += IOStream_write(io, str, n); + k += IOStream_print(io, "%c%s%c", c_data_quote, d, c_data_quote); + return k; +} + +/** Print a string as a quoted string. + * + * @param io stream + * @param str string + * @param n length + * @return bytes written or error code + */ +int _string_print_string(IOStream *io, char *str, int n){ + int k = 0; + + k += IOStream_print(io, "\""); + if(str){ + char *s, *t; + for(s = str, t = str + n; s < t; s++){ + if(*s < ' ' || *s >= 127 ){ + switch(*s){ + case '\a': k += IOStream_print(io, "\\a"); break; + case '\b': k += IOStream_print(io, "\\b"); break; + case '\f': k += IOStream_print(io, "\\f"); break; + case '\n': k += IOStream_print(io, "\\n"); break; + case '\r': k += IOStream_print(io, "\\r"); break; + case '\t': k += IOStream_print(io, "\\t"); break; + case '\v': k += IOStream_print(io, "\\v"); break; + default: + // Octal escape; + k += IOStream_print(io, "\\%o", *s); + break; + } + } else if(*s == c_double_quote || + *s == c_single_quote || + *s == c_escape){ + k += IOStream_print(io, "\\%c", *s); + } else { + k+= IOStream_print(io, "%c", *s); + } + } + } + k += IOStream_print(io, "\""); + return k; +} + /** Print a string to a stream, with escapes if necessary. * * @param io stream to print to * @param str string + * @param n string length * @param flags print flags * @return number of bytes written */ -int _string_print(IOStream *io, char *str, unsigned flags){ +int _string_print(IOStream *io, char *str, int n, unsigned flags){ int k = 0; - if((flags & PRINT_RAW) || !needs_escapes(str, flags)){ - k += IOStream_print(io, str); + if((flags & PRINT_COUNTED)){ + k = _string_print_counted(io, str, n); + } else if((flags & PRINT_RAW) || !needs_escapes(str, n, flags)){ + k = _string_print_raw(io, str, n); + } else if(n > 50){ + k = _string_print_quoted(io, str, n); } else { - k += IOStream_print(io, "\""); - if(str){ - char *s; - for(s = str; *s; s++){ - if(*s < ' ' || *s >= 127 ){ - switch(*s){ - case '\a': k += IOStream_print(io, "\\a"); break; - case '\b': k += IOStream_print(io, "\\b"); break; - case '\f': k += IOStream_print(io, "\\f"); break; - case '\n': k += IOStream_print(io, "\\n"); break; - case '\r': k += IOStream_print(io, "\\r"); break; - case '\t': k += IOStream_print(io, "\\t"); break; - case '\v': k += IOStream_print(io, "\\v"); break; - default: - // Octal escape; - k += IOStream_print(io, "\\%o", *s); - break; - } - } else if(*s == c_double_quote || - *s == c_single_quote || - *s == c_escape){ - k += IOStream_print(io, "\\%c", *s); - } else { - k+= IOStream_print(io, "%c", *s); - } - } - } - k += IOStream_print(io, "\""); + k = _string_print_string(io, str, n); } return k; } @@ -550,7 +742,14 @@ int _string_print(IOStream *io, char *str, unsigned flags){ * @return number of bytes written */ int string_print(IOStream *io, Sxpr obj, unsigned flags){ - return _string_print(io, OBJ_STRING(obj), flags); + return _string_print(io, + OBJ_STRING(obj)->data, + OBJ_STRING(obj)->len, + flags); +} + +int string_eq(char *s, int s_n, char *t, int t_n){ + return (s_n == t_n) && (memcmp(s, t, s_n) == 0); } /** Compare an sxpr with a string for equality. @@ -563,9 +762,13 @@ int string_equal(Sxpr x, Sxpr y){ int ok = 0; ok = eq(x,y); if(ok) goto exit; - ok = has_type(y, T_STRING) && !strcmp(OBJ_STRING(x), OBJ_STRING(y)); + ok = has_type(y, T_STRING) && + string_eq(OBJ_STRING(x)->data, OBJ_STRING(x)->len, + OBJ_STRING(y)->data, OBJ_STRING(y)->len); if(ok) goto exit; - ok = has_type(y, T_ATOM) && !strcmp(OBJ_STRING(x), atom_name(y)); + ok = has_type(y, T_ATOM) && + string_eq(OBJ_STRING(x)->data, OBJ_STRING(x)->len, + atom_name(y), atom_length(y)); exit: return ok; } @@ -613,15 +816,38 @@ int cons_push(Sxpr *list, Sxpr elt){ void cons_free(Sxpr obj){ Sxpr next; for(; CONSP(obj); obj = next){ - next = CDR(obj); - objfree(CAR(obj)); - hfree(obj); + next = CDR(obj); + objfree(CAR(obj)); + hfree(obj); } if(!NULLP(obj)){ - objfree(obj); + objfree(obj); } } +/** Copy a cons. Recursively copies the car and cdr. + * + * @param obj to copy + */ +Sxpr cons_copy(Sxpr obj){ + Sxpr v = ONULL; + Sxpr l = ONULL, x = ONONE; + for(l = obj; CONSP(l); l = CDR(l)){ + x = objcopy(CAR(l)); + if(NOMEMP(x)) goto exit; + x = cons_new(x, v); + if(NOMEMP(x)) goto exit; + v = x; + } + v = nrev(v); + exit: + if(NOMEMP(x)){ + objfree(v); + v = ONOMEM; + } + return v; +} + /** Free a cons and its cdr cells, but not the car sxprs. * Does nothing if called on something that is not a cons. * @@ -630,8 +856,8 @@ void cons_free(Sxpr obj){ void cons_free_cells(Sxpr obj){ Sxpr next; for(; CONSP(obj); obj = next){ - next = CDR(obj); - hfree(obj); + next = CDR(obj); + hfree(obj); } } @@ -698,26 +924,26 @@ int cons_length(Sxpr obj){ */ Sxpr nrev(Sxpr l){ if(CONSP(l)){ - // Iterate down the cells in the list making the cdr of - // each cell point to the previous cell. The last cell - // is the head of the reversed list. - Sxpr prev = ONULL; - Sxpr cell = l; - Sxpr next; - - while(1){ - next = CDR(cell); - CDR(cell) = prev; - if(!CONSP(next)) break; - prev = cell; - cell = next; - } - l = cell; + // Iterate down the cells in the list making the cdr of + // each cell point to the previous cell. The last cell + // is the head of the reversed list. + Sxpr prev = ONULL; + Sxpr cell = l; + Sxpr next; + + while(1){ + next = CDR(cell); + CDR(cell) = prev; + if(!CONSP(next)) break; + prev = cell; + cell = next; + } + l = cell; } return l; } -/** Print the null sxpr. +/** Print the null sxpr. * * @param io stream to print to * @param obj to print @@ -761,6 +987,30 @@ static int bool_print(IOStream *io, Sxpr obj, unsigned flags){ return IOStream_print(io, (OBJ_UINT(obj) ? k_true : k_false)); } +/** Print an error. + * + * @param io stream to print to + * @param obj to print + * @param flags print flags + * @return number of bytes written + */ +static int err_print(IOStream *io, Sxpr obj, unsigned flags){ + int err = OBJ_INT(obj); + if(err < 0) err = -err; + return IOStream_print(io, "[error:%d:%s]", err, strerror(err)); +} + +/** Print the 'nomem' sxpr. + * + * @param io stream to print to + * @param obj to print + * @param flags print flags + * @return number of bytes written + */ +static int nomem_print(IOStream *io, Sxpr obj, unsigned flags){ + return IOStream_print(io, "[ENOMEM]"); +} + int sxprp(Sxpr obj, Sxpr name){ return CONSP(obj) && objequal(CAR(obj), name); } @@ -781,8 +1031,8 @@ Sxpr sxpr_name(Sxpr obj){ } int sxpr_is(Sxpr obj, char *s){ - if(ATOMP(obj)) return !strcmp(atom_name(obj), s); - if(STRINGP(obj)) return !strcmp(string_string(obj), s); + if(ATOMP(obj)) return string_eq(atom_name(obj), atom_length(obj), s, strlen(s)); + if(STRINGP(obj)) return string_eq(string_string(obj), string_length(obj), s, strlen(s)); return 0; } @@ -915,11 +1165,11 @@ static int sym_equal_fn(void *x, void *y){ */ static void sym_free_fn(HashTable *table, HTEntry *entry){ if(entry){ - objfree(((ObjAtom*)entry->value)->name); - HTEntry_free(entry); + objfree(((ObjAtom*)entry->value)->name); + HTEntry_free(entry); } } - + /** Initialize the symbol table. * * @return 0 on sucess, error code otherwise @@ -929,7 +1179,7 @@ static int init_symbols(void){ if(symbols){ symbols->key_hash_fn = sym_hash_fn; symbols->key_equal_fn = sym_equal_fn; - symbols->entry_free_fn = sym_free_fn; + symbols->entry_free_fn = sym_free_fn; return 0; } return -1; @@ -950,8 +1200,8 @@ void cleanup_symbols(void){ Sxpr get_symbol(char *sym){ HTEntry *entry; if(!symbols){ - if(init_symbols()) return ONOMEM; - return ONULL; + if(init_symbols()) return ONOMEM; + return ONULL; } entry = HashTable_get_entry(symbols, sym); if(entry){ @@ -969,10 +1219,10 @@ Sxpr get_symbol(char *sym){ Sxpr intern(char *sym){ Sxpr symbol = get_symbol(sym); if(NULLP(symbol)){ - if(!symbols) return ONOMEM; + if(!symbols) return ONOMEM; symbol = atom_new(sym); if(!NOMEMP(symbol)){ - OBJ_ATOM(symbol)->interned = TRUE; + OBJ_ATOM(symbol)->interned = TRUE; HashTable_add(symbols, atom_name(symbol), get_ptr(symbol)); } } diff --git a/tools/libxutil/sxpr.h b/tools/libxutil/sxpr.h index 761b8b2da7..c9acd7b25f 100644 --- a/tools/libxutil/sxpr.h +++ b/tools/libxutil/sxpr.h @@ -52,15 +52,80 @@ typedef struct Sxpr { /** Sxpr type. */ TypeCode type; union { - /** Sxpr value. */ + /** Sxpr value. */ unsigned long ul; - /** Pointer. */ + /** Pointer. */ void *ptr; } v; } Sxpr; -/** Sxpr type to indicate out of memory. */ -#define T_NOMEM ((TypeCode)-1) +/** Get the integer value from an sxpr. + * + * @param obj sxpr + * @return value + */ +static inline unsigned long get_ul(Sxpr obj){ + return obj.v.ul; +} + +/** Get the pointer value from an sxpr. + * + * @param obj sxpr + * @return value + */ +static inline void * get_ptr(Sxpr obj){ + return obj.v.ptr; +} + +/** Create an sxpr containing a pointer. + * + * @param ty typecode + * @param val pointer + * @return sxpr + */ +static inline Sxpr obj_ptr(TypeCode ty, void *val){ + return (Sxpr){ .type= ty, .v= { .ptr= val } }; +} + +/** Create an sxpr containing an integer. + * + * @param ty typecode + * @param val integer + * @return sxpr + */ +static inline Sxpr obj_ul(TypeCode ty, unsigned long val){ + return (Sxpr){ .type= ty, .v= { .ul= val } }; +} + +/** Get the type of an sxpr. + * + * @param obj sxpr + * @return type + */ +static inline TypeCode get_type(Sxpr obj){ + return obj.type; +} + +/** Check the type of an sxpr. + * + * @param obj sxpr + * @param type to check + * @return 1 if has the type, 0 otherwise + */ +static inline int has_type(Sxpr obj, TypeCode type){ + return get_type(obj) == type; +} + +/** Compare sxprs for literal equality of type and value. + * + * @param x sxpr to compare + * @param y sxpr to compare + * @return 1 if equal, 0 otherwise + */ +static inline int eq(Sxpr x, Sxpr y){ + return ((get_type(x) == get_type(y)) && (get_ul(x) == get_ul(y))); +} + /** The 'unspecified' sxpr. */ #define T_NONE ((TypeCode)0) /** The empty list. */ @@ -79,6 +144,13 @@ typedef struct Sxpr { /** An error. */ #define T_ERR ((TypeCode)40) +/** Sxpr type to indicate out of memory. */ +#define T_NOMEM ((TypeCode)41) + +typedef struct ObjString { + int len; + char data[]; +} ObjString; /** An atom. */ typedef struct ObjAtom { @@ -93,41 +165,27 @@ typedef struct ObjCons { Sxpr cdr; } ObjCons; -/** A vector. */ -typedef struct ObjVector { - int n; - Sxpr data[0]; -} ObjVector; - /** Flags for sxpr printing. */ enum PrintFlags { PRINT_RAW = 0x001, PRINT_TYPE = 0x002, PRINT_PRETTY = 0x004, - PRINT_NUM = 0x008, + PRINT_COUNTED = 0x008, + PRINT_ADDR = 0x010, }; +extern int _string_print(IOStream *io, char *str, int n, unsigned flags); +extern int _string_print_raw(IOStream *io, char *str, int n); +extern int _string_print_counted(IOStream *io, char *str, int n); +extern int _string_print_quoted(IOStream *io, char *str, int n); +extern int _string_print_string(IOStream *io, char *str, int n); + /** An integer sxpr. * * @param ty type * @param val integer value */ -#define OBJI(ty, val) (Sxpr){ type: (ty), v: { ul: (val) }} - -/** A pointer sxpr. - * If the pointer is non-null, returns an sxpr containing it. - * If the pointer is null, returns ONOMEM. - * - * @param ty type - * @param val pointer - */ -#define OBJP(ty, val) ((val) ? (Sxpr){ type: (ty), v: { ptr: (val) }} : ONOMEM) - -/** Make an integer sxpr containing a pointer. - * - * @param val pointer - */ -#define PTR(val) OBJP(T_UINT, (void*)(val)) +#define OBJI(ty, val) obj_ul(ty, val) /** Make an integer sxpr. * @param x value @@ -155,6 +213,40 @@ enum PrintFlags { /** True constant. */ #define OTRUE OBJI(T_BOOL, 1) +/** A pointer sxpr. + * If the pointer is non-null, returns an sxpr containing it. + * If the pointer is null, returns ONOMEM. + * + * @param ty type + * @param val pointer + */ +static inline Sxpr OBJP(int ty, void *val){ + return (val ? obj_ptr(ty, val) : ONOMEM); +} + +/** Make an integer sxpr containing a pointer. + * + * @param val pointer + */ +#define PTR(val) OBJP(T_UINT, (void*)(val)) + +/** Allocate some memory and return an sxpr containing it. + * Returns ONOMEM if allocation failed. + * + * @param n number of bytes to allocate + * @param ty typecode + * @return sxpr + */ +#define halloc(_n, _ty) OBJP(_ty, allocate(_n)) + +/** Allocate an sxpr containing a pointer to the given type. + * + * @param _ctype type (uses sizeof to determine how many bytes to allocate) + * @param _tycode typecode + * @return sxpr, ONOMEM if allocation failed + */ +#define HALLOC(_ctype, _tycode) halloc(sizeof(_ctype), _tycode) + /* Recognizers for the various sxpr types. */ #define ATOMP(obj) has_type(obj, T_ATOM) #define BOOLP(obj) has_type(obj, T_BOOL) @@ -176,7 +268,7 @@ enum PrintFlags { /* Conversions of sxprs to their values. * No checking is done. */ -#define OBJ_STRING(x) ((char*)get_ptr(x)) +#define OBJ_STRING(x) ((ObjString*)get_ptr(x)) #define OBJ_CONS(x) ((ObjCons*)get_ptr(x)) #define OBJ_ATOM(x) ((ObjAtom*)get_ptr(x)) #define OBJ_SET(x) ((ObjSet*)get_ptr(x)) @@ -188,73 +280,6 @@ enum PrintFlags { #define CDAR(x) (CDR(CAR(x))) #define CDDR(x) (CDR(CDR(x))) -/** Get the integer value from an sxpr. - * - * @param obj sxpr - * @return value - */ -static inline unsigned long get_ul(Sxpr obj){ - return obj.v.ul; -} - -/** Get the pointer value from an sxpr. - * - * @param obj sxpr - * @return value - */ -static inline void * get_ptr(Sxpr obj){ - return obj.v.ptr; -} - -/** Create an sxpr containing a pointer. - * - * @param type typecode - * @param val pointer - * @return sxpr - */ -static inline Sxpr obj_ptr(TypeCode type, void *val){ - return (Sxpr){ type: type, v: { ptr: val } }; -} - -/** Create an sxpr containing an integer. - * - * @param type typecode - * @param val integer - * @return sxpr - */ -static inline Sxpr obj_ul(TypeCode type, unsigned long val){ - return (Sxpr){ type: type, v: { ul: val } }; -} - -/** Get the type of an sxpr. - * - * @param obj sxpr - * @return type - */ -static inline TypeCode get_type(Sxpr obj){ - return obj.type; -} - -/** Check the type of an sxpr. - * - * @param obj sxpr - * @param type to check - * @return 1 if has the type, 0 otherwise - */ -static inline int has_type(Sxpr obj, TypeCode type){ - return get_type(obj) == type; -} - -/** Compare sxprs for literal equality of type and value. - * - * @param x sxpr to compare - * @param y sxpr to compare - * @return 1 if equal, 0 otherwise - */ -static inline int eq(Sxpr x, Sxpr y){ - return ((get_type(x) == get_type(y)) && (get_ul(x) == get_ul(y))); -} - /** Checked version of CAR * * @param x sxpr @@ -273,28 +298,10 @@ static inline Sxpr cdr(Sxpr x){ return (CONSP(x) ? CDR(x) : ONULL); } -/** Allocate some memory and return an sxpr containing it. - * Returns ONOMEM if allocation failed. - * - * @param n number of bytes to allocate - * @param ty typecode - * @return sxpr - */ -static inline Sxpr halloc(size_t n, TypeCode ty){ - return OBJP(ty, allocate(n)); -} - -/** Allocate an sxpr containing a pointer to the given type. - * - * @param ty type (uses sizeof to determine how many bytes to allocate) - * @param code typecode - * @return sxpr, ONOMEM if allocation failed - */ -#define HALLOC(ty, code) halloc(sizeof(ty), code) - typedef int ObjPrintFn(IOStream *io, Sxpr obj, unsigned flags); typedef int ObjEqualFn(Sxpr obj, Sxpr other); typedef void ObjFreeFn(Sxpr obj); +typedef Sxpr ObjCopyFn(Sxpr obj); /** An sxpr type definition. */ typedef struct SxprType { @@ -304,6 +311,7 @@ typedef struct SxprType { ObjPrintFn *print; ObjEqualFn *equal; ObjFreeFn *free; + ObjCopyFn *copy; } SxprType; @@ -321,6 +329,7 @@ static inline void hfree(Sxpr x){ extern int objprint(IOStream *io, Sxpr x, unsigned flags); extern int objequal(Sxpr x, Sxpr y); extern void objfree(Sxpr x); +extern Sxpr objcopy(Sxpr x); extern void cons_free_cells(Sxpr obj); extern Sxpr intern(char *s); @@ -341,8 +350,10 @@ extern Sxpr cons_remove_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v); extern Sxpr atom_new(char *name); extern char * atom_name(Sxpr obj); +extern int atom_length(Sxpr obj); extern Sxpr string_new(char *s); +extern Sxpr string_new_n(char *s, int n); extern char * string_string(Sxpr obj); extern int string_length(Sxpr obj); @@ -405,15 +416,20 @@ static inline Sxpr mkbool(int b){ #define k_true "true" #define k_false "false" -#define c_var '$' #define c_escape '\\' #define c_single_quote '\'' #define c_double_quote '"' #define c_string_open c_double_quote #define c_string_close c_double_quote -#define c_data_open '[' -#define c_data_close ']' -#define c_binary '*' + +#define c_data_open '<' +#define c_data_quote '<' +#define c_data_count '*' +//#define c_data_open '[' +//#define c_data_close ']' +//#define c_binary '*' + +#define c_var '$' #define c_eval '!' #define c_concat_open '{' #define c_concat_close '}' diff --git a/tools/libxutil/sxpr_parser.c b/tools/libxutil/sxpr_parser.c index d32ef959b3..870f68f1a1 100644 --- a/tools/libxutil/sxpr_parser.c +++ b/tools/libxutil/sxpr_parser.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001 - 2004 Mike Wray + * Copyright (C) 2001 - 2005 Mike Wray * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as @@ -26,6 +26,8 @@ # include #endif +#include "sys_net.h" + #include "iostream.h" #include "lexis.h" #include "sxpr_parser.h" @@ -42,45 +44,24 @@ * @author Mike Wray */ +#ifdef DEBUG #define dprintf(fmt, args...) IOStream_print(iostdout, "[DEBUG] %s" fmt, __FUNCTION__, ##args) +#else +#define dprintf(fmt, args...) do{ }while(0) +#endif + #undef printf #define printf(fmt, args...) IOStream_print(iostdout, fmt, ##args) -static void reset(Parser *z); -static int inputchar(Parser *p, char c); -static int savechar(Parser *p, char c); -extern void parse_error(Parser *in); -extern void parse_error_id(Parser *in, ParseErrorId id); - -static int begin_start(Parser *p, char c); static int state_start(Parser *p, char c); -static int end_start(Parser *p); - -static int begin_comment(Parser *p, char c); -static int state_comment(Parser *p, char c); -static int end_comment(Parser *p); - -static int begin_string(Parser *p, char c); -static int state_string(Parser *p, char c); -static int end_string(Parser *p); -static int state_escape(Parser *p, char c); -static int state_octal(Parser *p, char c); -static int state_hex(Parser *p, char c); - -static int begin_atom(Parser *p, char c); -static int state_atom(Parser *p, char c); -static int end_atom(Parser *p); - -static int state_list(Parser *p, char c); -static int begin_list(Parser *p, char c); -static int end_list(Parser *p); +static int begin_start(Parser *p, char c); /** Print a parse error. * * @param in parser * @param msg format followed by printf arguments */ -void eprintf(Parser *in, char *msg, ...){ +static void eprintf(Parser *in, char *msg, ...){ va_list args; if(in->error_out){ va_start(args, msg); @@ -94,7 +75,7 @@ void eprintf(Parser *in, char *msg, ...){ * @param in parser * @param msg format followed by printf arguments */ -void wprintf(Parser *in, char *msg, ...){ +static void wprintf(Parser *in, char *msg, ...){ va_list args; if(in->error_out){ va_start(args, msg); @@ -107,8 +88,8 @@ void wprintf(Parser *in, char *msg, ...){ /** Record defining the message for a parse error. */ typedef struct { - ParseErrorId id; - char *message; + ParseErrorId id; + char *message; } ParseError; /** Format for printing parse error messages. */ @@ -116,156 +97,243 @@ typedef struct { /** Message catalog for the parse error codes. */ static ParseError catalog[] = { - { PARSE_ERR_UNSPECIFIED, "unspecified error" }, - { PARSE_ERR_NOMEM, "out of memory" }, - { PARSE_ERR_UNEXPECTED_EOF, "unexpected end of input" }, - { PARSE_ERR_TOKEN_TOO_LONG, "token too long" }, - { PARSE_ERR_INVALID_SYNTAX, "syntax error" }, - { PARSE_ERR_INVALID_ESCAPE, "invalid escape" }, - { 0, NULL } + { PARSE_ERR_UNSPECIFIED, "unspecified error" }, + { PARSE_ERR_NOMEM, "out of memory" }, + { PARSE_ERR_UNEXPECTED_EOF, "unexpected end of input" }, + { PARSE_ERR_TOKEN_TOO_LONG, "token too long" }, + { PARSE_ERR_INVALID_SYNTAX, "syntax error" }, + { PARSE_ERR_INVALID_ESCAPE, "invalid escape" }, + { 0, NULL } }; /** Number of entries in the message catalog. */ const static int catalog_n = sizeof(catalog)/sizeof(ParseError); -void ParserState_free(ParserState *z){ - if(!z) return; - objfree(z->val); - deallocate(z); +/** Set the parser error stream. + * Parse errors are reported on the the error stream if it is non-null. + * + * @param z parser + * @param error_out error stream + */ +void Parser_set_error_stream(Parser *z, IOStream *error_out){ + z->error_out = error_out; } -int ParserState_new(ParserStateFn *fn, char *name, - ParserState *parent, ParserState **val){ - int err = 0; - ParserState *z; - z = ALLOCATE(ParserState); - if(z){ - z->name = name; - z->fn = fn; - z->parent = parent; - z->val = ONULL; - } else { - err = -ENOMEM; +/** Get the parser error message for an error code. + * + * @param id error code + * @return error message (empty string if the code is unknown) + */ +static char *get_message(ParseErrorId id){ + int i; + for(i = 0; i < catalog_n; i++){ + if(id == catalog[i].id){ + return catalog[i].message; + } } - if(!err) *val = z; - return err; + return ""; } -/** Free a parser. - * No-op if the parser is null. +/** Get the line number. * - * @param z parser + * @param in parser */ -void Parser_free(Parser *z){ - if(!z) return; - objfree(z->val); - z->val = ONONE; - deallocate(z); +static int get_line(Parser *in){ + return in->line_no; } -/** Create a new parser. The error stream defaults to null. +/** Get the column number. + * + * @param in parser */ -Parser * Parser_new(void){ - Parser *z = ALLOCATE(Parser); - int err = -ENOMEM; - - if(!z) goto exit; - err = 0; - reset(z); - exit: - if(err){ - Parser_free(z); - z = NULL; - } - return z; +static int get_column(Parser *in){ + return in->char_no; } -/** Get the next character. - * Records the character read in the parser, - * and sets the line and character counts. +/** Get the line number the current token started on. + * + * @param in parser + */ +static int get_tok_line(Parser *in){ + return in->tok_begin_line; +} + +/** Get the column number the current token started on. + * + * @param in parser + */ +static int get_tok_column(Parser *in){ + return in->tok_begin_char; +} + +/** Return the current token. + * The return value points at the internal buffer, so + * it must not be modified (or freed). Use copy_token() if you need a copy. * * @param p parser - * @return error flag: 0 on success, non-zero on error + * @return token */ -static int inputchar(Parser *p, char c){ - int err = 0; - if(c=='\n'){ - p->line_no++; - p->char_no = 0; - } else { - p->char_no++; +char *peek_token(Parser *p){ + return p->tok; +} + +int token_len(Parser *p){ + return p->tok_end - p->tok; +} + +/** Return a copy of the current token. + * The returned value should be freed when finished with. + * + * @param p parser + * @return copy of token + */ +char *copy_token(Parser *p){ + int n = token_len(p); + char *buf = allocate(n + 1); + if(buf){ + memcpy(buf, peek_token(p), n); + buf[n] = '\0'; } - return err; + return buf; } -static int savechar(Parser *p, char c){ - int err = 0; - if(p->buf_i >= p->buf_n){ - err = -ENOMEM; - goto exit; +void new_token(Parser *p){ + memset(p->buf, 0, p->buf_end - p->buf); + p->tok = p->buf; + p->tok_end = p->tok; + p->tok_begin_line = p->line_no; + p->tok_begin_char = p->char_no; +} + +/** Report a parse error. + * Does nothing if the error stream is null or there is no error. + * + * @param in parser + */ +static void report_error(Parser *in){ + if(in->error_out && in->err){ + char *msg = get_message(in->err); + char *tok = peek_token(in); + IOStream_print(in->error_out, PARSE_ERR_FMT, + get_tok_line(in), get_tok_column(in), msg); + if(tok && tok[0]){ + IOStream_print(in->error_out, " '%s'", tok); + } + IOStream_print(in->error_out, "\n"); } - p->buf[p->buf_i] = c; - p->buf_i++; - exit: - return err; } -int Parser_input_char(Parser *p, char c){ - int err = 0; - if(at_eof(p)){ - //skip; - } else { - inputchar(p, c); +/** Get the error message for the current parse error code. + * Does nothing if there is no error. + * + * @param in parser + * @param buf where to place the message + * @param n maximum number of characters to place in buf + * @return current error code (zero for no error) + */ +int Parser_error_message(Parser *in, char *buf, int n){ + if(in->err){ + char *msg = get_message(in->err); + snprintf(buf, n, PARSE_ERR_FMT, get_tok_line(in), + get_tok_column(in), msg); } - if(!p->state){ - err = begin_start(p, c); - if(err) goto exit; + return in->err; +} + +/** Flag a parse error. All subsequent reads will fail. + * Does not change the parser error code if it is already set. + * + * @param in parser + * @param id error code + */ +int Parser_error_id(Parser *in, ParseErrorId id){ + if(!in->err){ + in->err = id; + report_error(in); } - err = p->state->fn(p, c); - exit: - return err; + return -EINVAL; } -int Parser_input_eof(Parser *p){ - int err = 0; - p->eof = 1; - err = Parser_input_char(p, IOSTREAM_EOF); - return err; +/** Flag an unspecified parse error. + * + * @param in parser + */ +int Parser_error(Parser *in){ + return Parser_error_id(in, PARSE_ERR_INVALID_SYNTAX); } -int Parser_input(Parser *p, char *buf, int buf_n){ - int err = 0; - int i = 0; - if(buf_n <= 0){ - err = Parser_input_eof(p); - goto exit; - } - for(i = 0; ierr > 0); } -int Parser_push(Parser *p, ParserStateFn *fn, char *name){ - int err = 0; - err = ParserState_new(fn, name, p->state, &p->state); +/** Test if the parser is at end of input. + * + * @param in parser + * @return 1 if at EOF, 0 otherwise + */ +int Parser_at_eof(Parser *p){ + return p->eof; +} + +void ParserState_free(ParserState *z){ + if(!z) return; + objfree(z->val); + deallocate(z); +} + +int ParserState_new(ParserStateFn *fn, char *name, + ParserState *parent, ParserState **val){ + int err = -ENOMEM; + ParserState *z; + z = ALLOCATE(ParserState); + if(!z) goto exit; + z->name = name; + z->fn = fn; + z->parent = parent; + z->val = ONULL; + err = 0; + exit: + *val = (err ? NULL : z); return err; } - -int Parser_pop(Parser *p){ - int err = 0; + +void Parser_pop(Parser *p){ ParserState *s = p->state; + if(!s) return; p->state = s->parent; if (p->start_state == s) { p->start_state = NULL; } ParserState_free(s); - return err; } +/** Free a parser. + * No-op if the parser is null. + * + * @param z parser + */ +void Parser_free(Parser *z){ + if(!z) return; + // Hmmm. Need to free states, but careful about double free of values. + while(z->state){ + objfree(z->state->val); + Parser_pop(z); + } + if(z->buf) deallocate(z->buf); + objfree(z->val); + z->val = ONONE; + deallocate(z); +} + +int Parser_push(Parser *p, ParserStateFn *fn, char *name){ + return ParserState_new(fn, name, p->state, &p->state); +} + int Parser_return(Parser *p){ int err = 0; Sxpr val = ONONE; @@ -275,8 +343,7 @@ int Parser_return(Parser *p){ } val = p->state->val; p->state->val = ONONE; - err = Parser_pop(p); - if(err) goto exit; + Parser_pop(p); if(p->state){ err = cons_push(&p->state->val, val); } else { @@ -290,52 +357,102 @@ int Parser_return(Parser *p){ return err; } -/** Determine if a character is a separator. +/** Reset the fields of a parser to initial values. * - * @param p parser - * @param c character to test - * @return 1 if a separator, 0 otherwise + * @param z parser */ -static int is_separator(Parser *p, char c){ - return in_sep_class(c); +static void reset(Parser *z){ + // leave flags + // leave error_out + while(z->state){ + Parser_pop(z); + } + z->val = ONONE; + z->eof = 0; + z->err = 0; + z->line_no = 1; + z->char_no = 0; + memset(z->buf, 0, z->buf_end - z->buf); + z->tok = z->buf; + z->tok_end = z->tok; + z->tok_begin_line = 0; + z->tok_begin_char = 0; + z->start_state = NULL; } -/** Return the current token. - * The return value points at the internal buffer, so - * it must not be modified (or freed). Use copy_token() if you need a copy. - * - * @param p parser - * @return token +/** Create a new parser. The error stream defaults to null. */ -char *peek_token(Parser *p){ - return p->buf; +Parser * Parser_new(void){ + Parser *z = ALLOCATE(Parser); + int n = PARSER_BUF_SIZE; + int err = -ENOMEM; + + if(!z) goto exit; + z->buf = allocate(n); + if(!z->buf) goto exit; + err = 0; + z->buf_end = z->buf + n; + z->begin = begin_start; + reset(z); + exit: + if(err){ + Parser_free(z); + z = NULL; + } + return z; } -/** Return a copy of the current token. - * The returned value should be freed when finished with. +/** Get the next character. + * Records the character read in the parser, + * and sets the line and character counts. * * @param p parser - * @return copy of token + * @return error flag: 0 on success, non-zero on error */ -char *copy_token(Parser *p){ - return strdup(peek_token(p)); -} - -static int do_intern(Parser *p){ +static int input_char(Parser *p, char c){ int err = 0; - Sxpr obj = intern(peek_token(p)); - if(NOMEMP(obj)){ - err = -ENOMEM; + if(c=='\n'){ + p->line_no++; + p->char_no = 0; } else { - p->state->val = obj; + p->char_no++; } return err; } -static int do_string(Parser *p){ +int save_char(Parser *p, char c){ + int err = 0; + if(p->tok_end >= p->buf_end){ + int buf_n = (p->buf_end - p->buf) + PARSER_BUF_INCREMENT; + char *buf = allocate(buf_n); + if(!buf){ + err = -ENOMEM; + goto exit; + } + memcpy(buf, p->buf, p->tok_end - p->buf); + p->buf_end = buf + buf_n; + p->tok = buf + (p->tok - p->buf); + p->tok_end = buf + (p->tok_end - p->buf); + deallocate(p->buf); + p->buf = buf; + } + *p->tok_end++ = c; + exit: + return err; +} + +/** Determine if a character is a separator. + * + * @param p parser + * @param c character to test + * @return 1 if a separator, 0 otherwise + */ +static int is_separator(Parser *p, char c){ + return in_sep_class(c); +} + +int Parser_set_value(Parser *p, Sxpr obj){ int err = 0; - Sxpr obj; - obj = string_new(peek_token(p)); if(NOMEMP(obj)){ err = -ENOMEM; } else { @@ -343,15 +460,33 @@ static int do_string(Parser *p){ } return err; } + +int Parser_intern(Parser *p){ + Sxpr obj = intern(peek_token(p)); + return Parser_set_value(p, obj); +} -void newtoken(Parser *p){ - memset(p->buf, 0, p->buf_n); - p->buf_i = 0; - p->tok_begin_line = p->line_no; - p->tok_begin_char = p->char_no; +int Parser_atom(Parser *p){ + Sxpr obj = atom_new(peek_token(p)); + return Parser_set_value(p, obj); +} + +int Parser_string(Parser *p){ + Sxpr obj = string_new_n(peek_token(p), token_len(p)); + return Parser_set_value(p, obj); +} + +int Parser_data(Parser *p){ + Sxpr obj = string_new_n(peek_token(p), token_len(p)); + return Parser_set_value(p, obj); +} + +int Parser_uint(Parser *p){ + unsigned int x = htonl(*(unsigned int *)peek_token(p)); + return Parser_set_value(p, OINT(x)); } -int get_escape(char c, char *d){ +static int get_escape(char c, char *d){ int err = 0; switch(c){ case 'a': *d = '\a'; break; @@ -377,15 +512,18 @@ int Parser_ready(Parser *p){ Sxpr Parser_get_val(Parser *p){ Sxpr v = ONONE; if(CONSP(p->val)){ - v = CAR(p->val); - p->val = CDR(p->val); - } else if (CONSP(p->start_state->val)){ + } else if (p->start_state && CONSP(p->start_state->val)){ p->val = p->start_state->val; p->val = nrev(p->val); p->start_state->val = ONULL; - v = CAR(p->val); - p->val = CDR(p->val); - } + } else { + goto exit; + } + Sxpr w = p->val; + v = CAR(w); + p->val = CDR(w); + hfree(w); + exit: return v; } @@ -401,151 +539,51 @@ Sxpr Parser_get_all(Parser *p){ } return v; } - -int begin_start(Parser *p, char c){ - int err = 0; - err = Parser_push(p, state_start, "start"); - if(err) goto exit; - p->start_state = p->state; - exit: - return err; -} -int state_start(Parser *p, char c){ +static int state_comment(Parser *p, char c){ int err = 0; - if(at_eof(p)){ - err = end_start(p); - } else if(in_space_class(c)){ - //skip - } else if(in_comment_class(c)){ - begin_comment(p, c); - } else if(c == c_list_open){ - begin_list(p, c); - } else if(c == c_list_close){ - parse_error(p); - err = -EINVAL; - } else if(in_string_quote_class(c)){ - begin_string(p, c); - } else if(in_printable_class(c)){ - begin_atom(p, c); - } else if(c == 0x04){ - //ctrl-D, EOT: end-of-text. - Parser_input_eof(p); + if(c == '\n' || Parser_at_eof(p)){ + Parser_pop(p); } else { - parse_error(p); - err = -EINVAL; + err = input_char(p, c); } return err; } -int end_start(Parser *p){ - int err = 0; - err = Parser_return(p); - return err; -} - -int begin_comment(Parser *p, char c){ +static int begin_comment(Parser *p, char c){ int err = 0; err = Parser_push(p, state_comment, "comment"); if(err) goto exit; - err = inputchar(p, c); - exit: - return err; -} - -int state_comment(Parser *p, char c){ - int err = 0; - if(c == '\n' || at_eof(p)){ - err = end_comment(p); - } else { - err = inputchar(p, c); - } - return err; -} - -int end_comment(Parser *p){ - return Parser_pop(p); -} - -int begin_string(Parser *p, char c){ - int err = 0; - err = Parser_push(p, state_string, "string"); - if(err) goto exit; - newtoken(p); - p->state->delim = c; - exit: - return err; -} - -int state_string(Parser *p, char c){ - int err = 0; - if(at_eof(p)){ - parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF); - err = -EINVAL; - } else if(c == p->state->delim){ - err = end_string(p); - } else if(c == '\\'){ - err = Parser_push(p, state_escape, "escape"); - } else { - err = savechar(p, c); - } - return err; -} - -int end_string(Parser *p){ - int err = 0; - err = do_string(p); - if(err) goto exit; - err = Parser_return(p); + err = input_char(p, c); exit: return err; } -int state_escape(Parser *p, char c){ +static int end_string(Parser *p){ int err = 0; - char d; - if(at_eof(p)){ - parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF); - err = -EINVAL; - goto exit; - } - if(get_escape(c, &d) == 0){ - err = savechar(p, d); - if(err) goto exit; - err = Parser_pop(p); - } else if(c == 'x'){ - p->state->fn = state_hex; - p->state->ival = 0; - p->state->count = 0; - } else { - p->state->fn = state_octal; - p->state->ival = 0; - p->state->count = 0; - err = Parser_input_char(p, c); - } + err = Parser_string(p); + if(err) goto exit; + err = Parser_return(p); exit: return err; } -int octaldone(Parser *p){ +static int octaldone(Parser *p){ int err = 0; char d = (char)(p->state->ival & 0xff); - err = Parser_pop(p); - if(err) goto exit; + Parser_pop(p); err = Parser_input_char(p, d); - exit: return err; } -int octaldigit(Parser *p, char c){ +static int octaldigit(Parser *p, int d){ int err = 0; p->state->ival *= 8; - p->state->ival += c - '0'; + p->state->ival += d; p->state->count++; if(err) goto exit; if(p->state->ival < 0 || p->state->ival > 0xff){ - parse_error(p); - err = -EINVAL; + err = Parser_error(p); goto exit; } if(p->state->count == 3){ @@ -555,14 +593,13 @@ int octaldigit(Parser *p, char c){ return err; } -int state_octal(Parser *p, char c){ +static int state_octal(Parser *p, char c){ int err = 0; - if(at_eof(p)){ - parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF); - err = -EINVAL; + if(Parser_at_eof(p)){ + err = Parser_error_id(p, PARSE_ERR_UNEXPECTED_EOF); goto exit; } else if('0' <= c && c <= '7'){ - err = octaldigit(p, c); + err = octaldigit(p, c - '0'); } else { err = octaldone(p); if(err) goto exit; @@ -572,25 +609,22 @@ int state_octal(Parser *p, char c){ return err; } -int hexdone(Parser *p){ +static int hexdone(Parser *p){ int err = 0; char d = (char)(p->state->ival & 0xff); - err = Parser_pop(p); - if(err) goto exit; + Parser_pop(p); err = Parser_input_char(p, d); - exit: return err; } -int hexdigit(Parser *p, char c, char d){ +static int hexdigit(Parser *p, int d){ int err = 0; p->state->ival *= 16; - p->state->ival += c - d; + p->state->ival += d; p->state->count++; if(err) goto exit; if(p->state->ival < 0 || p->state->ival > 0xff){ - parse_error(p); - err = -EINVAL; + err = Parser_error(p); goto exit; } if(p->state->count == 2){ @@ -600,20 +634,19 @@ int hexdigit(Parser *p, char c, char d){ return err; } -int state_hex(Parser *p, char c){ +static int state_hex(Parser *p, char c){ int err = 0; - if(at_eof(p)){ - parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF); - err = -EINVAL; + if(Parser_at_eof(p)){ + err = Parser_error_id(p, PARSE_ERR_UNEXPECTED_EOF); goto exit; } else if('0' <= c && c <= '9'){ - err = hexdigit(p, c, '0'); + err = hexdigit(p, c - '0'); } else if('A' <= c && c <= 'F'){ - err = hexdigit(p, c, 'A'); + err = hexdigit(p, c - 'A' + 10); } else if('a' <= c && c <= 'f'){ - err = hexdigit(p, c, 'a'); + err = hexdigit(p, c - 'a' + 10); } else if(p->state->count){ - err =hexdone(p); + err = hexdone(p); if(err) goto exit; Parser_input_char(p, c); } @@ -621,19 +654,67 @@ int state_hex(Parser *p, char c){ return err; } -int begin_atom(Parser *p, char c){ +static int state_escape(Parser *p, char c){ int err = 0; - err = Parser_push(p, state_atom, "atom"); + char d; + if(Parser_at_eof(p)){ + err = Parser_error_id(p, PARSE_ERR_UNEXPECTED_EOF); + goto exit; + } + if(get_escape(c, &d) == 0){ + err = save_char(p, d); + if(err) goto exit; + Parser_pop(p); + } else if(c == 'x'){ + p->state->fn = state_hex; + p->state->ival = 0; + p->state->count = 0; + } else { + p->state->fn = state_octal; + p->state->ival = 0; + p->state->count = 0; + err = Parser_input_char(p, c); + } + exit: + return err; +} + +static int state_string(Parser *p, char c){ + int err = 0; + if(Parser_at_eof(p)){ + err = Parser_error_id(p, PARSE_ERR_UNEXPECTED_EOF); + } else if(c == p->state->delim){ + err = end_string(p); + } else if(c == '\\'){ + err = Parser_push(p, state_escape, "escape"); + } else { + err = save_char(p, c); + } + return err; +} + +static int begin_string(Parser *p, char c){ + int err = 0; + err = Parser_push(p, state_string, "string"); + if(err) goto exit; + new_token(p); + p->state->delim = c; + exit: + return err; +} + +static int end_atom(Parser *p){ + int err = 0; + err = Parser_atom(p); if(err) goto exit; - newtoken(p); - err = savechar(p, c); + err = Parser_return(p); exit: return err; } -int state_atom(Parser *p, char c){ +static int state_atom(Parser *p, char c){ int err = 0; - if(at_eof(p)){ + if(Parser_at_eof(p)){ err = end_atom(p); } else if(is_separator(p, c) || in_space_class(c) || @@ -642,258 +723,232 @@ int state_atom(Parser *p, char c){ if(err) goto exit; err = Parser_input_char(p, c); } else { - err = savechar(p, c); + err = save_char(p, c); } exit: return err; } -int end_atom(Parser *p){ +static int begin_atom(Parser *p, char c){ int err = 0; - err = do_intern(p); + err = Parser_push(p, state_atom, "atom"); if(err) goto exit; - err = Parser_return(p); + new_token(p); + err = save_char(p, c); exit: return err; } -int state_list(Parser *p, char c){ +static int end_data(Parser *p){ int err = 0; - if(at_eof(p)){ - parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF); - err = -EINVAL; - } else if(c == c_list_close){ - p->state->val = nrev(p->state->val); - err = end_list(p); - } else { - err = state_start(p, c); - } + err = Parser_data(p); + if(err) goto exit; + err = Parser_return(p); + exit: return err; - -} - -int begin_list(Parser *p, char c){ - return Parser_push(p, state_list, "list"); -} - -int end_list(Parser *p){ - return Parser_return(p); -} - -/** Reset the fields of a parser to initial values. - * - * @param z parser - */ -static void reset(Parser *z){ - IOStream *error_out = z->error_out; - int flags = z->flags; - memzero(z, sizeof(Parser)); - z->buf_n = sizeof(z->buf) - 1; - z->buf_i = 0; - z->line_no = 1; - z->char_no = 0; - z->error_out = error_out; - z->flags = flags; -} - -/** Set the parser error stream. - * Parse errors are reported on the the error stream if it is non-null. - * - * @param z parser - * @param error_out error stream - */ -void set_error_stream(Parser *z, IOStream *error_out){ - if(z){ - z->error_out = error_out; - } } -/** Get the parser error message for an error code. - * - * @param id error code - * @return error message (empty string if the code is unknown) - */ -static char *get_message(ParseErrorId id){ - int i; - for(i=0; istate->count){ + err = end_data(p); } - } - return ""; -} - -/** Get the line number. - * - * @param in parser - */ -int get_line(Parser *in){ - return in->line_no; -} - -/** Get the column number. - * - * @param in parser - */ -int get_column(Parser *in){ - return in->char_no; + exit: + return err; } -/** Get the line number the current token started on. - * - * @param in parser - */ -int get_tok_line(Parser *in){ - return in->tok_begin_line; +static int counted_data_count(Parser *p, char c){ + int err = 0; + if(c == p->state->delim){ + new_token(p); + p->state->count = p->state->ival; + p->state->fn = counted_data; + } else if('0' <= c && c <= '9'){ + p->state->ival *= 10; + p->state->ival += c - '0'; + } else { + err = -EINVAL; + } + return err; } -/** Get the column number the current token started on. - * - * @param in parser - */ -int get_tok_column(Parser *in){ - return in->tok_begin_char; +static int quoted_data(Parser *p, char c){ + int err = 0; + int count = p->state->count; + err = save_char(p, c); + if(err) goto exit; + // Check that buf is longer than delim and + // ends with delim. If so, trim delim off and return. + if((token_len(p) >= count) && + !memcmp(p->tok_end - count, p->buf, count)){ + p->tok_end -= count; + end_data(p); + } + exit: + return err; } -/** Report a parse error. - * Does nothing if the error stream is null or there is no error. - * - * @param in parser - */ -static void report_error(Parser *in){ - if(in->error_out && in->err){ - char *msg = get_message(in->err); - char *tok = peek_token(in); - IOStream_print(in->error_out, PARSE_ERR_FMT, - get_tok_line(in), get_tok_column(in), msg); - if(tok && tok[0]){ - IOStream_print(in->error_out, " '%s'", tok); +static int quoted_data_delim(Parser *p, char c){ + // Saves the delim in the token buffer. + int err = 0; + err = save_char(p, c); + if(err) goto exit; + if(c == p->state->delim){ + p->state->fn = quoted_data; + p->state->count = token_len(p); + // Advance the token pointer past the delim. + p->tok = p->tok_end; } - IOStream_print(in->error_out, "\n"); - } + exit: + return err; } -/** Get the error message for the current parse error code. - * Does nothing if there is no error. - * - * @param in parser - * @param buf where to place the message - * @param n maximum number of characters to place in buf - * @return current error code (zero for no error) - */ -int parse_error_message(Parser *in, char *buf, int n){ - if(in->err){ - char *msg = get_message(in->err); - snprintf(buf, n, PARSE_ERR_FMT, get_tok_line(in), get_tok_column(in), msg); +static int state_data(Parser *p, char c){ + // Quoted data: + // <state->delim = c; + p->state->fn = counted_data_count; + p->state->ival = 0; + new_token(p); + break; + case c_data_quote: + p->state->delim = c; + p->state->fn = quoted_data_delim; + new_token(p); + err = save_char(p, c); + break; + default: + err = Parser_error(p); + break; } - return in->err; + return err; } -/** Flag an unspecified parse error. All subsequent reads will fail. - * - * @param in parser - */ -void parse_error(Parser *in){ - parse_error_id(in, PARSE_ERR_INVALID_SYNTAX); +static int begin_data(Parser *p, char c){ + int err = 0; + err = Parser_push(p, state_data, "data"); + if(err) goto exit; + new_token(p); + exit: + return err; } -/** Flag a parse error. All subsequent reads will fail. - * Does not change the parser error code if it is already set. - * - * @param in parser - * @param id error code - */ -void parse_error_id(Parser *in, ParseErrorId id){ - if(!in->err){ - in->err = id; - report_error(in); +static int state_list(Parser *p, char c){ + int err = 0; + dprintf(">\n"); + if(Parser_at_eof(p)){ + err = Parser_error_id(p, PARSE_ERR_UNEXPECTED_EOF); + } else if(c == c_list_close){ + p->state->val = nrev(p->state->val); + err = Parser_return(p); + } else { + err = state_start(p, c); } + dprintf("< err=%d\n", err); + return err; + } -/** Test if the parser's error flag is set. - * - * @param in parser - * @return 1 if set, 0 otherwise - */ -int has_error(Parser *in){ - return (in->err > 0); -} - -/** Test if the parser is at end of input. - * - * @param in parser - * @return 1 if at EOF, 0 otherwise - */ -int at_eof(Parser *p){ - return p->eof; +static int begin_list(Parser *p, char c){ + return Parser_push(p, state_list, "list"); } -#ifdef SXPR_PARSER_MAIN -/* Stuff for standalone testing. */ - -#include "file_stream.h" -#include "string_stream.h" - -extern int stringof(Sxpr exp, char **s); -int child_string(Sxpr exp, Sxpr key, char **s){ +static int state_start(Parser *p, char c){ int err = 0; - Sxpr val = sxpr_child_value(exp, key, ONONE); - err = stringof(val, s); + dprintf(">\n"); + if(Parser_at_eof(p)){ + err = Parser_return(p); + } else if(in_space_class(c)){ + //skip + } else if(in_comment_class(c)){ + begin_comment(p, c); + } else if(c == c_list_open){ + begin_list(p, c); + } else if(c == c_list_close){ + err = Parser_error(p); + } else if(in_string_quote_class(c)){ + begin_string(p, c); + } else if(c == c_data_open){ + begin_data(p, c); + } else if(in_printable_class(c)){ + begin_atom(p, c); + } else if(c == 0x04){ + //ctrl-D, EOT: end-of-text. + Parser_input_eof(p); + } else { + err = Parser_error(p); + } + dprintf("< err=%d\n", err); return err; } -extern int intof(Sxpr exp, int *v); -int child_int(Sxpr exp, Sxpr key, int *v){ +int begin_start(Parser *p, char c){ int err = 0; - Sxpr val = sxpr_child_value(exp, key, ONONE); - err = intof(val, v); + dprintf(">\n"); + err = Parser_push(p, state_start, "start"); + if(err) goto exit; + p->start_state = p->state; + exit: + dprintf("< err=%d\n", err); return err; } -int eval_vnet(Sxpr exp){ +int Parser_input_char(Parser *p, char c){ int err = 0; - Sxpr oid = intern("id"); - int id; - err = child_int(exp, oid, &id); - if(err) goto exit; - dprintf("> vnet id=%d\n", id); - exit: - dprintf("< err=%d\n", err); + if(Parser_at_eof(p)){ + //skip; + } else { + input_char(p, c); + } + if(!p->state){ + err = p->begin(p, c); + if(err) goto exit; + } + err = p->state->fn(p, c); + exit: return err; } -int eval_connect(Sxpr exp){ +int Parser_input_eof(Parser *p){ int err = 0; - Sxpr ovif = intern("vif"); - Sxpr ovnet = intern("vnet"); - char *vif; - int vnet; - - err = child_string(exp, ovif, &vif); - if(err) goto exit; - err = child_int(exp, ovnet, &vnet); - if(err) goto exit; - dprintf("> connect vif=%s vnet=%d\n", vif, vnet); - exit: - dprintf("< err=%d\n", err); + p->eof = 1; + err = Parser_input_char(p, IOSTREAM_EOF); return err; } -int eval(Sxpr exp){ +int Parser_input(Parser *p, char *buf, int buf_n){ int err = 0; - Sxpr oconnect = intern("connect"); - Sxpr ovnet = intern("vnet"); - - if(sxpr_elementp(exp, ovnet)){ - err = eval_vnet(exp); - } else if(sxpr_elementp(exp, oconnect)){ - err = eval_connect(exp); - } else { - err = -EINVAL; + int i = 0; + dprintf("> |%s|\n", buf); + if(buf_n <= 0){ + err = Parser_input_eof(p); + goto exit; } + for(i = 0; i < buf_n; i++){ + err = Parser_input_char(p, buf[i]); + if(err) goto exit; + } + exit: + err = (err < 0 ? err : buf_n); + dprintf("< err=%d\n", err); return err; } +#ifdef SXPR_PARSER_MAIN +/* Stuff for standalone testing. */ + +#include "file_stream.h" +//#include "string_stream.h" + /** Main program for testing. * Parses input and prints it. * @@ -907,14 +962,16 @@ int main(int argc, char *argv[]){ char buf[1024]; int k; Sxpr obj; - //Sxpr l, x; int i = 0; pin = Parser_new(); - set_error_stream(pin, iostdout); + Parser_set_error_stream(pin, iostdout); dprintf("> parse...\n"); while(1){ - k = fread(buf, 1, 1, stdin); + k = fread(buf, 1, 100, stdin); + if(k>=0){ + buf[k+1] = '\0'; + } err = Parser_input(pin, buf, k); while(Parser_ready(pin)){ obj = Parser_get_val(pin); @@ -923,12 +980,6 @@ int main(int argc, char *argv[]){ } if(k <= 0) break; } -/* obj = Parser_get_all(pin); */ -/* for(l = obj ; CONSP(l); l = CDR(l)){ */ -/* x = CAR(l); */ -/* objprint(iostdout, x, 0); printf("\n"); */ -/* eval(x); */ -/* } */ dprintf("> err=%d\n", err); return 0; } diff --git a/tools/libxutil/sxpr_parser.h b/tools/libxutil/sxpr_parser.h index 0a3fde55fd..591ed95572 100644 --- a/tools/libxutil/sxpr_parser.h +++ b/tools/libxutil/sxpr_parser.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001 - 2004 Mike Wray + * Copyright (C) 2001 - 2005 Mike Wray * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as @@ -25,10 +25,13 @@ * Sxpr parsing definitions. */ -/** Size of a parser input buffer. - * Tokens read must fit into this size (including trailing null). +/** Initial size of a parser input buffer. */ -#define PARSER_BUF_SIZE 4096 +#define PARSER_BUF_SIZE 512 + +/** Input buffer size increment (when it's full). + */ +#define PARSER_BUF_INCREMENT 512 struct Parser; typedef int ParserStateFn(struct Parser *, char c); @@ -43,13 +46,14 @@ typedef struct ParserState { char *name; } ParserState; -/** Structure representing an input source for the parser. - * Can read from any IOStream implementation. - */ typedef struct Parser { + /** Initial state function. */ + ParserStateFn *begin; + /** Parse value. */ Sxpr val; /** Error reporting stream (null for no reports). */ IOStream *error_out; + /** End-of-file flag, */ int eof; /** Error flag. Non-zero if there has been a read error. */ int err; @@ -57,13 +61,11 @@ typedef struct Parser { int line_no; /** Column number of input (reset on new line). */ int char_no; - /** Lookahead character. */ - char c; /** Buffer for reading tokens. */ - char buf[PARSER_BUF_SIZE]; - /** Size of token buffer. */ - int buf_n; - int buf_i; + char *buf; + char *buf_end; + char *tok; + char *tok_end; /** Line the last token started on. */ int tok_begin_line; /** Character number the last token started on. */ @@ -95,7 +97,7 @@ typedef enum { * @param in parser * @param flags flags mask */ -inline static void parser_flags_raise(Parser *in, int flags){ +inline static void Parser_flags_raise(Parser *in, int flags){ in->flags |= flags; } @@ -104,7 +106,7 @@ inline static void parser_flags_raise(Parser *in, int flags){ * @param in parser * @param flags flags mask */ -inline static void parser_flags_lower(Parser *in, int flags){ +inline static void Parser_flags_lower(Parser *in, int flags){ in->flags &= ~flags; } @@ -112,7 +114,7 @@ inline static void parser_flags_lower(Parser *in, int flags){ * * @param in parser */ -inline static void parser_flags_clear(Parser *in){ +inline static void Parser_flags_clear(Parser *in){ in->flags = 0; } @@ -121,14 +123,32 @@ extern Parser * Parser_new(void); extern int Parser_input(Parser *p, char *buf, int buf_n); extern int Parser_input_eof(Parser *p); extern int Parser_input_char(Parser *p, char c); -extern void set_error_stream(Parser *z, IOStream *error_out); - -extern int parse_error_message(Parser *in, char *buf, int n); -extern int has_error(Parser *in); -extern int at_eof(Parser *in); - -int Parser_ready(Parser *p); -Sxpr Parser_get_val(Parser *p); -Sxpr Parser_get_all(Parser *p); +extern void Parser_set_error_stream(Parser *z, IOStream *error_out); + +extern int Parser_error_message(Parser *in, char *buf, int n); +extern int Parser_has_error(Parser *in); +extern int Parser_at_eof(Parser *in); + +extern int Parser_ready(Parser *p); +extern Sxpr Parser_get_val(Parser *p); +extern Sxpr Parser_get_all(Parser *p); + +/* Internal parser api. */ +void Parser_pop(Parser *p); +int Parser_push(Parser *p, ParserStateFn *fn, char *name); +int Parser_return(Parser *p); +int Parser_at_eof(Parser *p); +int Parser_error(Parser *in); +int Parser_set_value(Parser *p, Sxpr val); +int Parser_intern(Parser *p); +int Parser_string(Parser *p); +int Parser_data(Parser *p); +int Parser_uint(Parser *p); + +char *peek_token(Parser *p); +char *copy_token(Parser *p); +void new_token(Parser *p); +int save_char(Parser *p, char c); +int token_len(Parser *p); #endif /* ! _XUTIL_SXPR_PARSER_H_ */ diff --git a/tools/libxutil/sys_string.c b/tools/libxutil/sys_string.c index 13a90dfd7d..22a8ae3688 100644 --- a/tools/libxutil/sys_string.c +++ b/tools/libxutil/sys_string.c @@ -49,6 +49,27 @@ inline static const char * convert_set_base(const char *s, int *base){ return s; } +/** Set the sign to use for converting a string to a number. + * Value is 1 for positive, -1 for negative. + * + * @param s input string + * @param sign where to put the sign + * @return rest of s to parse as a number + */ +inline static const char * convert_set_sign(const char *s, int *sign){ + *sign = 1; + if(s){ + if(*s == '+'){ + *sign = 1; + s++; + } else if (*s == '-'){ + *sign = -1; + s++; + } + } + return s; +} + /** Get the numerical value of a digit in the given base. * * @param c digit character @@ -103,6 +124,40 @@ int convert_atoul(const char *str, unsigned long *val){ return err; } +/** Convert a string to a long by parsing it as a number. + * Will accept hex or decimal in usual C syntax. + * + * @param str input string + * @param val where to put the result + * @return 0 if converted OK, negative otherwise + */ +int convert_atol(const char *str, long *val){ + int err = 0; + unsigned long v = 0; + int base, sign = 1; + const char *s = str; + + if(!s) { + err = -EINVAL; + goto exit; + } + s = convert_set_sign(s, &sign); + s = convert_set_base(s, &base); + for( ; !err && *s; s++){ + int digit = convert_get_digit(*s, base); + if(digit<0){ + err = -EINVAL; + goto exit; + } + v *= base; + v += digit; + } + if(sign < 0) v = -v; + exit: + *val = (err ? 0 : v); + return err; +} + /** Combine a directory path with a relative path to produce * a new path. * diff --git a/tools/libxutil/sys_string.h b/tools/libxutil/sys_string.h index ea60401168..88d9d8db61 100644 --- a/tools/libxutil/sys_string.h +++ b/tools/libxutil/sys_string.h @@ -86,6 +86,7 @@ static inline size_t strnlen(const char *s, size_t n){ /*============================================================================*/ extern int convert_atoul(const char *s, unsigned long *v); +extern int convert_atol(const char *s, long *v); extern int path_concat(char *s, char *t, char **val); #endif /* !_XUTIL_SYS_STRING_H_ */ diff --git a/tools/python/xen/xend/server/SrvDaemon.py b/tools/python/xen/xend/server/SrvDaemon.py index 557c18ecdd..3709f17edd 100644 --- a/tools/python/xen/xend/server/SrvDaemon.py +++ b/tools/python/xen/xend/server/SrvDaemon.py @@ -60,7 +60,6 @@ class Daemon: if not pm: continue xm = xendre.match(pm.group('cmd')) if not xm: continue - #print 'pid=', pm.group('pid'), 'cmd=', pm.group('cmd') pids.append(int(pm.group('pid'))) return pids @@ -313,7 +312,7 @@ class Daemon: os.setuid(pwd.getpwnam(XEND_USER)[2]) return 0 except KeyError, error: - print "Error: no such user '%s'" % XEND_USER + print >>sys.stderr, "Error: no such user '%s'" % XEND_USER return 1 def stop(self): @@ -328,7 +327,6 @@ class Daemon: self.listenChannels() servers = SrvServer.create() self.daemonize() - print 'running serverthread...' servers.start() except Exception, ex: print >>sys.stderr, 'Exception starting xend:', ex @@ -342,14 +340,12 @@ class Daemon: def listenChannels(self): def virqReceived(virq): - print 'virqReceived>', virq eserver.inject('xend.virq', virq) self.channelF.setVirqHandler(virqReceived) self.channelF.start() def exit(self, rc=0): - #reactor.disconnectAll() if self.channelF: self.channelF.stop() # Calling sys.exit() raises a SystemExit exception, which only diff --git a/tools/python/xen/xend/server/event.py b/tools/python/xen/xend/server/event.py index ce76c149b0..e0096d2d95 100644 --- a/tools/python/xen/xend/server/event.py +++ b/tools/python/xen/xend/server/event.py @@ -3,17 +3,13 @@ import StringIO from xen.web import reactor, protocol -from xen.lowlevel import xu - from xen.xend import sxp from xen.xend import PrettyPrint -from xen.xend import EventServer -eserver = EventServer.instance() +from xen.xend import EventServer; eserver = EventServer.instance() from xen.xend.XendError import XendError - from xen.xend import XendRoot; xroot = XendRoot.instance() -DEBUG = 1 +DEBUG = 0 class EventProtocol(protocol.Protocol): """Asynchronous handler for a connected event socket. @@ -30,7 +26,7 @@ class EventProtocol(protocol.Protocol): self.pretty = 0 # For debugging subscribe to everything and make output pretty. - self.subscribe(['*']) + #self.subscribe(['*']) self.pretty = 1 def dataReceived(self, data): @@ -45,10 +41,7 @@ class EventProtocol(protocol.Protocol): except SystemExit: raise except: - if DEBUG: - raise - else: - self.send_error() + self.send_error() def loseConnection(self): if self.transport: @@ -73,7 +66,11 @@ class EventProtocol(protocol.Protocol): return 0 def send_result(self, res): - return self.send_reply(['ok', res]) + if res is None: + resp = ['ok'] + else: + resp = ['ok', res] + return self.send_reply(resp) def send_error(self): (extype, exval) = sys.exc_info()[:2] @@ -129,7 +126,6 @@ class EventProtocol(protocol.Protocol): def op_pretty(self, name, req): self.pretty = 1 - return ['ok'] def op_console_disconnect(self, name, req): id = sxp.child_value(req, 'id') @@ -137,7 +133,6 @@ class EventProtocol(protocol.Protocol): raise XendError('Missing console id') id = int(id) self.daemon.console_disconnect(id) - return ['ok'] def op_info(self, name, req): val = ['info'] @@ -151,13 +146,11 @@ class EventProtocol(protocol.Protocol): # (sys.subscribe event*) # Subscribe to the events: self.subscribe(v[1:]) - return ['ok'] def op_sys_inject(self, name, v): # (sys.inject event) event = v[1] eserver.inject(sxp.name(event), event) - return ['ok'] def op_trace(self, name, v): mode = (v[1] == 'on') @@ -181,6 +174,27 @@ class EventProtocol(protocol.Protocol): import controller controller.DEBUG = (mode == 'on') + def op_domain_ls(self, name, v): + xd = xroot.get_component("xen.xend.XendDomain") + return xd.domain_ls() + + def op_domain_configure(self, name, v): + domid = sxp.child_value(v, "dom") + config = sxp.child_value(v, "config") + if domid is None: + raise XendError("missing domain id") + if config is None: + raise XendError("missing domain config") + xd = xroot.get_component("xen.xend.XendDomain") + xd.domain_configure(domid, config) + + def op_domain_unpause(self, name, v): + domid = sxp.child_value(v, "dom") + if domid is None: + raise XendError("missing domain id") + xd = xroot.get_component("xen.xend.XendDomain") + xd.domain_unpause(domid) + class EventFactory(protocol.ServerFactory): """Asynchronous handler for the event server socket. """ diff --git a/tools/xfrd/Make.xfrd b/tools/xfrd/Make.xfrd index 3bbfe4d5d6..a3f13a4fd4 100644 --- a/tools/xfrd/Make.xfrd +++ b/tools/xfrd/Make.xfrd @@ -6,6 +6,7 @@ UTIL_LIB = libutil.a UTIL_LIB_SRC = UTIL_LIB_SRC += allocate.c UTIL_LIB_SRC += enum.c +UTIL_LIB_SRC += fd_stream.c UTIL_LIB_SRC += file_stream.c UTIL_LIB_SRC += gzip_stream.c UTIL_LIB_SRC += hash_table.c @@ -19,7 +20,7 @@ UTIL_LIB_SRC += sxpr_parser.c UTIL_LIB_SRC += sys_net.c UTIL_LIB_SRC += sys_string.c #UTIL_LIB_SRC += util.c -UTIL_LIB_SRC += xdr.c +#UTIL_LIB_SRC += xdr.c #---------------------------------------------------------------------------- # Xfrd. diff --git a/tools/xfrd/Makefile b/tools/xfrd/Makefile index fb6f2ae244..949c6f915a 100644 --- a/tools/xfrd/Makefile +++ b/tools/xfrd/Makefile @@ -26,18 +26,11 @@ UTIL_LIB_OBJ = $(UTIL_LIB_SRC:.c=.o) XFRD_PROG_OBJ = $(XFRD_PROG_SRC:.c=.o) XFRD_PROG_OBJ += $(UTIL_LIB) -# Flag controlling whether to use stubs. -# Define to use stubs, undefine to use the real Xen functions. -#CPPFLAGS += -D _XEN_XFR_STUB_ - -ifeq ($(SXPR_DEBUG),1) -CPPFLAGS += -D _XEN_XFR_STUB_ -D SXPR_PARSER_MAIN -endif - CC := gcc CFLAGS += -Wall -Werror -O3 -fno-strict-aliasing CFLAGS += $(INCLUDES) + # Make gcc generate dependencies. CFLAGS += -Wp,-MD,.$(@F).d PROG_DEP = .*.d @@ -55,12 +48,6 @@ XFRD_LIBS += -L $(XEN_LIBXUTIL) -lxutil # zlib library. XFRD_LIBS += -lz -CURL_FLAGS = $(shell curl-config --cflags) -CURL_LIBS = $(shell curl-config --libs) -CFLAGS += $(CURL_FLAGS) -# libcurl libraries. -XFRD_LIBS += $(CURL_LIBS) - #$(warning XFRD_LIBS = $(XFRD_LIBS)) all: build diff --git a/tools/xfrd/connection.c b/tools/xfrd/connection.c index 36f2ca8475..7b493cdcfa 100644 --- a/tools/xfrd/connection.c +++ b/tools/xfrd/connection.c @@ -171,7 +171,7 @@ int Conn_sxpr(Conn *conn, Sxpr *sxpr){ dprintf(">\n"); if(!conn->parser){ conn->parser = Parser_new(); - set_error_stream(conn->parser, iostdout); + Parser_set_error_stream(conn->parser, iostdout); } while(!err && c >= 0 && !Parser_ready(conn->parser)){ c = IOStream_getc(conn->in); diff --git a/tools/xfrd/lzi_stream.c b/tools/xfrd/lzi_stream.c index fb72f7703b..b50b5c7953 100644 --- a/tools/xfrd/lzi_stream.c +++ b/tools/xfrd/lzi_stream.c @@ -475,7 +475,6 @@ static int lzi_close(IOStream *io){ */ static void lzi_free(IOStream *s){ LZIState *state = lzi_state(s); - IOStream_free(state->io); LZIState_free(state); s->data = NULL; } @@ -525,8 +524,8 @@ IOStream *lzi_stream_fdopen(int fd, const char *mode){ err = 0; exit: if(err){ - IOStream_free(io); - IOStream_free(zio); + IOStream_close(io); + IOStream_close(zio); zio = NULL; } return zio; diff --git a/tools/xfrd/xen_domain.c b/tools/xfrd/xen_domain.c index 8a374eba97..9f9d1f15a6 100644 --- a/tools/xfrd/xen_domain.c +++ b/tools/xfrd/xen_domain.c @@ -1,17 +1,18 @@ #include #include #include +#include +#include -#ifdef _XEN_XFR_STUB_ -typedef unsigned long u32; -#else #include "xc.h" #include "xc_io.h" -#endif + +#include "sxpr.h" +#include "sxpr_parser.h" +#include "file_stream.h" +#include "fd_stream.h" #include "xen_domain.h" -#include "marshal.h" -#include "xdr.h" #include "xfrd.h" #define MODULE_NAME "XFRD" @@ -33,7 +34,6 @@ int domain_configure(void *data, u32 dom, char *vmconfig, int vmconfig_n){ return xen_domain_configure(dom, vmconfig, vmconfig_n); } -#ifndef _XEN_XFR_STUB_ static int xc_handle = 0; int xcinit(void){ @@ -50,7 +50,6 @@ void xcfini(void){ xc_handle = 0; } } -#endif /** Write domain state. * @@ -62,31 +61,6 @@ int xen_domain_snd(Conn *xend, IOStream *io, char *vmconfig, int vmconfig_n, int live, int resource){ int err = 0; -#ifdef _XEN_XFR_STUB_ - char buf[1024]; - int n, k, d, buf_n; - dprintf("> dom=%d\n", dom); - err = marshal_uint32(io, dom); - if(err) goto exit; - err = marshal_string(io, vmconfig, vmconfig_n); - if(err) goto exit; - n = 32 * 1024 * 1024; - n = 32 * 1024; - buf_n = sizeof(buf); - err = marshal_uint32(io, n); - for(k = 0; k < n; k += d){ - d = n - k; - if(d > buf_n) d = buf_n; - err = marshal_bytes(io, buf, d); - if(err) goto exit; - dprintf("> k=%d n=%d\n", k, n); - } - - dom = 99; - err = domain_suspend(xend, dom); - IOStream_close(io); - exit: -#else XcIOContext _ioctxt = {}, *ioctxt = &_ioctxt; ioctxt->domain = dom; ioctxt->io = io; @@ -101,7 +75,6 @@ int xen_domain_snd(Conn *xend, IOStream *io, } ioctxt->resource = resource; err = xc_linux_save(xcinit(), ioctxt); -#endif dprintf("< err=%d\n", err); return err; } @@ -114,25 +87,6 @@ int xen_domain_rcv(IOStream *io, char **vmconfig, int *vmconfig_n, int *configured){ int err = 0; -#ifdef _XEN_XFR_STUB_ - char buf[1024]; - int n, k, d, buf_n; - dprintf(">\n"); - err = unmarshal_uint32(io, dom); - if(err) goto exit; - err = unmarshal_new_string(io, vmconfig, vmconfig_n); - if(err) goto exit; - err = unmarshal_uint32(io, &n); - buf_n = sizeof(buf); - for(k = 0; k < n; k += d){ - d = n - k; - if(d > buf_n) d = buf_n; - err = unmarshal_bytes(io, buf, d); - if(err) goto exit; - dprintf("> k=%d n=%d\n", k, n); - } - exit: -#else XcIOContext _ioctxt = {}, *ioctxt = &_ioctxt; dprintf(">\n"); ioctxt->io = io; @@ -147,137 +101,182 @@ int xen_domain_rcv(IOStream *io, *vmconfig = ioctxt->vmconfig; *vmconfig_n = ioctxt->vmconfig_n; *configured = (ioctxt->flags & XCFLAGS_CONFIGURE); -#endif dprintf("< err=%d\n", err); return err; } -#include -#include "http.h" +typedef struct xend { + int fd; + IOStream *io; + Parser *parser; + int seeneof; +} Xend; -/** Flag indicating whether we need to initialize libcurl. - */ -static int do_curl_global_init = 1; +char *xend_server_addr(void){ + char * val = getenv("XEND_EVENT_ADDR"); + return (val ? val : "/var/lib/xend/event-socket"); +} -/** Get a curl handle, initializing libcurl if needed. - * - * @return curl handle +/** Open a unix-domain socket to the xend server. */ -static CURL *curlinit(void){ - if(do_curl_global_init){ - do_curl_global_init = 0; - // Stop libcurl using the proxy. There's a curl option to - // set the proxy - but no option to defeat it. - unsetenv("http_proxy"); - curl_global_init(CURL_GLOBAL_ALL); +int xend_open_fd(void){ + struct sockaddr_un addr_un = { .sun_family = AF_UNIX }; + struct sockaddr *addr = (struct sockaddr*)&addr_un; + int addr_n = sizeof(addr_un); + int err = 0; + + int fd = socket(AF_UNIX, SOCK_STREAM, 0); + if(fd < 0){ + err = -errno; + perror("socket"); + goto exit; } - return curl_easy_init(); + strcpy(addr_un.sun_path, xend_server_addr()); + if(connect(fd, addr, addr_n) < 0){ + err = -errno; + perror("connect"); + goto exit; + } + exit: + if(err && (fd >= 0)){ + close(fd); + } + + return (err ? err : fd); } -/** Curl debug function. - */ -int curldebug(CURL *curl, curl_infotype ty, char *buf, int buf_n, void *data){ - // printf("%*s\n", buf_n, buf); /* Does not compile correctly on non 32bit platforms */ - fwrite(data, buf_n, 1, stdout); - printf("\n"); - return 0; +/** Close a connection to the server. + * + * @param xend connection +*/ +void xend_close(Xend *xend){ + if(!xend) return; + close(xend->fd); + Parser_free(xend->parser); } -/** Setup a curl handle with a url. - * Creates the url by formatting 'fmt' and the remaining arguments. +/** Open a connection to the server. * - * @param pcurl return parameter for the curl handle - * @param url url buffer - * @param url_n size of url - * @param fmt url format string, followed by parameters - * @return 0 on success, error code otherwise + * @param xend result parameter for the connection + * @return 0 on success, negative error code otherwise */ -static int curlsetup(CURL **pcurl, struct curl_slist **pheaders, char *url, int url_n, char *fmt, ...){ +int xend_open(Xend **xend){ int err = 0; - va_list args; - CURL *curl = NULL; - struct curl_slist *headers = NULL; - int n = 0; + Xend *val = ALLOCATE(Xend); - curl = curlinit(); - if(!curl){ - eprintf("> Could not init libcurl\n"); - err = -ENOMEM; - goto exit; - } - url_n -= 1; - va_start(args, fmt); - n = vsnprintf(url, url_n, fmt, args); - va_end(args); - if(n <= 0 || n >= url_n){ - err = -ENOMEM; - eprintf("> Out of memory in url\n"); + val->fd = xend_open_fd(); + + if(val->fd < 0){ + err = val->fd; goto exit; } - dprintf("> url=%s\n", url); -#if DEBUG - // Verbose. - curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); - // Call the debug function on data received. - curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, curldebug); -#else - // No progress meter. - curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1); - // Completely quiet. - curl_easy_setopt(curl, CURLOPT_MUTE, 1); -#endif - // Set the URL. - curl_easy_setopt(curl, CURLOPT_URL, url); - - headers = curl_slist_append(headers, "Expect:"); - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); - + val->io = fd_stream_new(val->fd); + val->parser = Parser_new(); exit: - if(err && curl){ - curl_easy_cleanup(curl); - curl = NULL; - } - *pcurl = curl; - if (pheaders) - *pheaders = headers; + if(err) xend_close(val); + *xend = (err ? NULL : val); return err; } -static void curlcleanup(CURL **pcurl, struct curl_slist **pheaders){ - if (*pcurl) - curl_easy_cleanup(*pcurl); - if (*pheaders) - curl_slist_free_all(*pheaders); - *pcurl = NULL; - *pheaders = NULL; +/** Read a response from a server connection. + */ +int xend_read_resp(Xend *xend, Sxpr *resp){ + int err = 0; + Sxpr val = ONONE; + char buf[1024]; + int buf_n = sizeof(buf), n; + + for( ; ; ){ + if(Parser_ready(xend->parser)){ + val = Parser_get_val(xend->parser); + goto exit; + } + if(xend->seeneof){ + err = -EIO; + goto exit; + } + memset(buf, 0, buf_n); + n = IOStream_read(xend->io, buf, 100); + if(n <= 0){ + xend->seeneof = 1; + err = Parser_input_eof(xend->parser); + } else { + err = Parser_input(xend->parser, buf, n); + } + } + exit: + *resp = (err < 0 ? ONONE : val); + return err; } -/** Make the http request stored in the curl handle and get - * the result code from the curl code and the http return code. + +/** Read a response from a server connection and decode the value. * - * @param curl curl handle - * @return 0 for success, error code otherwise + * @param xend server connection + * @param resp result parameter for the response value + * @return 0 on success, negative error code otherwise */ -int curlresult(CURL *curl){ +int xend_read(Xend *xend, Sxpr *resp){ int err = 0; - CURLcode curlcode = 0; - long httpcode = 0; + Sxpr val = ONONE; - curlcode = curl_easy_perform(curl); - if(curlcode){ - eprintf("> curlcode=%d\n", curlcode); - err = -EINVAL; - goto exit; - } - curl_easy_getinfo(curl, CURLINFO_HTTP_CODE, &httpcode); - if(httpcode != HTTP_OK){ - eprintf("> httpcode=%d\n", (int)httpcode); - err = -EINVAL; - goto exit; + dprintf(">\n"); + for( ; ; ){ + err = xend_read_resp(xend, &val); + if(err < 0) goto exit; + + if(sxpr_is(sxpr_name(val), "event")){ + // We don't care about events, try again. + err = 0; + continue; + } else if(sxpr_is(sxpr_name(val), "err")){ + eprintf("> "); objprint(iostderr, val, 0); fprintf(stderr, "\n"); + err = -EINVAL; + break; + } else { + err = 0; + val = sxpr_child0(val, ONULL); + break; + } } +#ifdef DEBUG + dprintf("> OK "); + objprint(iostdout, val, 0); + printf("\n"); +#endif exit: + if(resp){ + *resp = (err < 0 ? ONONE : val); + } + dprintf("> err=%d\n", err); return err; } +/** Send a request to the server and return the result value in resp. + * + * @param xend server connection + * @param resp result parameter for the response value + * @param format request format followed by args to print + * @return 0 on success, negative error code otherwise + */ +int xend_call(Xend *xend, Sxpr *resp, char *format, ...){ + va_list args; + int err; + + dprintf("> "); + va_start(args, format); +#ifdef DEBUG + vprintf(format, args); printf("\n"); +#endif + err = IOStream_vprint(xend->io, format, args); + va_end(args); + if(err < 0) goto exit; + IOStream_flush(xend->io); + err = xend_read(xend, resp); + exit: + dprintf("> err=%d\n", err); + return (err < 0 ? err : 0); +} + /** Get xend to list domains. * We use this to force xend to refresh its domain list. * @@ -285,18 +284,12 @@ int curlresult(CURL *curl){ */ int xen_domain_ls(void){ int err = 0; - CURL *curl = NULL; - struct curl_slist *headers = NULL; - char url[128] = {}; - int url_n = sizeof(url); - - dprintf(">\n"); - err = curlsetup(&curl, &headers, url, url_n, "http://localhost:%d/xend/domain", XEND_PORT); + Xend *xend = NULL; + err = xend_open(&xend); if(err) goto exit; - err = curlresult(curl); + err = xend_call(xend, NULL, "(domain.ls)"); exit: - curlcleanup(&curl, &headers); - dprintf("< err=%d\n", err); + xend_close(xend); return err; } @@ -309,49 +302,18 @@ int xen_domain_ls(void){ */ int xen_domain_configure(uint32_t dom, char *vmconfig, int vmconfig_n){ int err = 0; - CURL *curl = NULL; - struct curl_slist *headers = NULL; - char url[128] = {}; - int url_n = sizeof(url); - struct curl_httppost *form = NULL, *last = NULL; - CURLFORMcode formcode = 0; - + Xend *xend = NULL; dprintf("> dom=%u\n", dom); // List domains so that xend will update its domain list and notice the new domain. xen_domain_ls(); - - err = curlsetup(&curl, &headers, url, url_n, "http://localhost:%d/xend/domain/%u", XEND_PORT, dom); + // Now configure it. + err = xend_open(&xend); if(err) goto exit; - - // Config field - set from vmconfig. - formcode = curl_formadd(&form, &last, - CURLFORM_COPYNAME, "config", - CURLFORM_BUFFER, "config", - CURLFORM_BUFFERPTR, vmconfig, - CURLFORM_BUFFERLENGTH, vmconfig_n, - CURLFORM_CONTENTTYPE, "application/octet-stream", - CURLFORM_END); - if(formcode){ - eprintf("> Error adding config field.\n"); - goto exit; - } - // Op field. - formcode = curl_formadd(&form, &last, - CURLFORM_COPYNAME, "op", - CURLFORM_COPYCONTENTS, "configure", - CURLFORM_END); - if(formcode){ - eprintf("> Error adding op field.\n"); - err = -EINVAL; - goto exit; - } - // POST the form. - curl_easy_setopt(curl, CURLOPT_HTTPPOST, form); - err = curlresult(curl); + err = xend_call(xend, NULL, "(domain.configure (dom %d) (config %*s))", + dom, vmconfig_n, vmconfig); exit: - curlcleanup(&curl, &headers); - if(form) curl_formfree(form); dprintf("< err=%d\n", err); + xend_close(xend); return err; } @@ -362,34 +324,11 @@ int xen_domain_configure(uint32_t dom, char *vmconfig, int vmconfig_n){ */ int xen_domain_unpause(uint32_t dom){ int err = 0; - CURL *curl = NULL; - struct curl_slist *headers = NULL; - char url[128] = {}; - int url_n = sizeof(url); - struct curl_httppost *form = NULL, *last = NULL; - CURLFORMcode formcode = 0; - - dprintf("> dom=%u\n", dom); - - err = curlsetup(&curl, &headers, url, url_n, "http://localhost:%d/xend/domain/%u", XEND_PORT, dom); + Xend *xend = NULL; + err = xend_open(&xend); if(err) goto exit; - - // Op field. - formcode = curl_formadd(&form, &last, - CURLFORM_COPYNAME, "op", - CURLFORM_COPYCONTENTS, "unpause", - CURLFORM_END); - if(formcode){ - eprintf("> Error adding op field.\n"); - err = -EINVAL; - goto exit; - } - // POST the form. - curl_easy_setopt(curl, CURLOPT_HTTPPOST, form); - err = curlresult(curl); + err = xend_call(xend, NULL, "(domain.unpause (dom %d))", dom); exit: - curlcleanup(&curl, &headers); - if(form) curl_formfree(form); - dprintf("< err=%d\n", err); + xend_close(xend); return err; } diff --git a/tools/xfrd/xfrd.c b/tools/xfrd/xfrd.c index 89353e0e3b..2379b045c7 100644 --- a/tools/xfrd/xfrd.c +++ b/tools/xfrd/xfrd.c @@ -188,7 +188,6 @@ enum { XFR_MAX }; -#ifndef SXPR_PARSER_MAIN /** Short options. Options followed by ':' take an argument. */ static char *short_opts = (char[]){ OPT_PORT, ':', @@ -213,7 +212,6 @@ static Args _args = {}; /** Xfrd arguments. */ static Args *args = &_args; -#endif /** Initialize an array element for a constant to its string name. */ #define VALDEF(val) { val, #val } @@ -782,7 +780,6 @@ int xfr_save(Args *args, XfrState *state, Conn *xend, char *file){ exit: if(io){ IOStream_close(io); - IOStream_free(io); } if(err){ unlink(file); @@ -798,7 +795,7 @@ int xfr_save(Args *args, XfrState *state, Conn *xend, char *file){ int xfr_restore(Args *args, XfrState *state, Conn *xend, char *file){ int err = 0; IOStream *io = NULL; - int configured=0; + int configured = 0; dprintf("> file=%s\n", file); io = gzip_stream_fopen(file, "rb"); @@ -820,7 +817,6 @@ int xfr_restore(Args *args, XfrState *state, Conn *xend, char *file){ exit: if(io){ IOStream_close(io); - IOStream_free(io); } if(err){ xfr_error(xend, err); @@ -1215,7 +1211,6 @@ int xfrd_main(Args *args){ return err; } -#ifndef SXPR_PARSER_MAIN /** Parse command-line arguments and call the xfrd main program. * * @param arg argument count @@ -1271,4 +1266,3 @@ int main(int argc, char *argv[]){ } return (err ? 1 : 0); } -#endif -- 2.30.2